mirror of
https://github.com/horizon-rust/horizon.git
synced 2026-11-07 11:06:11 -10:00
Merge remote-tracking branch 'origin/main' into cg32/fix-9153
This commit is contained in:
commit
5eef8152d8
619 files changed
+118456
-4158
No files matched your search
+2
-2
@@ -868,7 +868,7 @@ Banners in End cities show as plain magenta instead of with their pattern.
|
||||
|
||||
<details><summary>Technical</summary>
|
||||
|
||||
Compare the banner block entities the End city templates place with vanilla's (`EndCityPieces`, the templates' block entity NBT, `BannerBlockEntity`'s patterns), in `crates/horizon-world/src/worldgen/structure/`. Issue [#1438](https://github.com/horizon-rust/horizon/issues/1438); possibly related: [#526](https://github.com/horizon-rust/horizon/issues/526).
|
||||
Compare the banner block entities the End city templates place with vanilla's (`EndCityPieces`, the templates' block entity NBT, `BannerBlockEntity`'s patterns), in `crates/horizon-world/src/worldgen/structure/`. Issue [#1438](https://github.com/horizon-rust/horizon/issues/1438); possibly related: [#526](https://github.com/horizon-rust/horizon/issues/526). The templates' block entities now keep their patterns ([#1928](https://github.com/horizon-rust/horizon/issues/1928)).
|
||||
|
||||
</details>
|
||||
|
||||
@@ -878,7 +878,7 @@ Armour and tools in End city chests should come enchanted, as in vanilla.
|
||||
|
||||
<details><summary>Technical</summary>
|
||||
|
||||
`loot.rs` implements `enchant_with_levels`: find why the End city chest table's rolls come out bare, and compare them with vanilla's for a few seeds. Issues [#1437](https://github.com/horizon-rust/horizon/issues/1437), [#1660](https://github.com/horizon-rust/horizon/issues/1660).
|
||||
`loot.rs` implements `enchant_with_levels`: find why the End city chest table's rolls come out bare, and compare them with vanilla's for a few seeds. Issues [#1437](https://github.com/horizon-rust/horizon/issues/1437), [#1660](https://github.com/horizon-rust/horizon/issues/1660). The loot's enchantment functions now reach every table that rolls ([#1911](https://github.com/horizon-rust/horizon/issues/1911), [#2037](https://github.com/horizon-rust/horizon/issues/2037)).
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
@@ -16,6 +16,8 @@ are in that folder (`LICENSE.MIT`, `LICENSE.APACHE`).
|
||||
|
||||
The GLSL frontend also resets the common type for each comma-separated declarator so one
|
||||
variable's array specifier does not change later variables.
|
||||
It also reads a struct member outside a constant expression through a pointer to the member,
|
||||
not out of a loaded copy of the whole struct, so a member an atomic function uses can be read.
|
||||
|
||||
## libmimalloc-sys and mimalloc
|
||||
|
||||
|
||||
@@ -160,6 +160,162 @@ impl ResourceSource for Bundled {
|
||||
"assets/horizon/lang/el_gr.json" => {
|
||||
include_str!("../../horizon-client/assets/horizon/lang/el_gr.json")
|
||||
}
|
||||
"assets/horizon/lang/ca_es.json" => {
|
||||
include_str!("../../horizon-client/assets/horizon/lang/ca_es.json")
|
||||
}
|
||||
"assets/horizon/lang/et_ee.json" => {
|
||||
include_str!("../../horizon-client/assets/horizon/lang/et_ee.json")
|
||||
}
|
||||
"assets/horizon/lang/lv_lv.json" => {
|
||||
include_str!("../../horizon-client/assets/horizon/lang/lv_lv.json")
|
||||
}
|
||||
"assets/horizon/lang/sl_si.json" => {
|
||||
include_str!("../../horizon-client/assets/horizon/lang/sl_si.json")
|
||||
}
|
||||
"assets/horizon/lang/sr_cs.json" => {
|
||||
include_str!("../../horizon-client/assets/horizon/lang/sr_cs.json")
|
||||
}
|
||||
"assets/horizon/lang/is_is.json" => {
|
||||
include_str!("../../horizon-client/assets/horizon/lang/is_is.json")
|
||||
}
|
||||
"assets/horizon/lang/af_za.json" => {
|
||||
include_str!("../../horizon-client/assets/horizon/lang/af_za.json")
|
||||
}
|
||||
"assets/horizon/lang/ms_my.json" => {
|
||||
include_str!("../../horizon-client/assets/horizon/lang/ms_my.json")
|
||||
}
|
||||
"assets/horizon/lang/be_by.json" => {
|
||||
include_str!("../../horizon-client/assets/horizon/lang/be_by.json")
|
||||
}
|
||||
"assets/horizon/lang/sr_sp.json" => {
|
||||
include_str!("../../horizon-client/assets/horizon/lang/sr_sp.json")
|
||||
}
|
||||
"assets/horizon/lang/az_az.json" => {
|
||||
include_str!("../../horizon-client/assets/horizon/lang/az_az.json")
|
||||
}
|
||||
"assets/horizon/lang/uz_uz.json" => {
|
||||
include_str!("../../horizon-client/assets/horizon/lang/uz_uz.json")
|
||||
}
|
||||
"assets/horizon/lang/kk_kz.json" => {
|
||||
include_str!("../../horizon-client/assets/horizon/lang/kk_kz.json")
|
||||
}
|
||||
"assets/horizon/lang/ka_ge.json" => {
|
||||
include_str!("../../horizon-client/assets/horizon/lang/ka_ge.json")
|
||||
}
|
||||
"assets/horizon/lang/hy_am.json" => {
|
||||
include_str!("../../horizon-client/assets/horizon/lang/hy_am.json")
|
||||
}
|
||||
"assets/horizon/lang/bs_ba.json" => {
|
||||
include_str!("../../horizon-client/assets/horizon/lang/bs_ba.json")
|
||||
}
|
||||
"assets/horizon/lang/mk_mk.json" => {
|
||||
include_str!("../../horizon-client/assets/horizon/lang/mk_mk.json")
|
||||
}
|
||||
"assets/horizon/lang/sq_al.json" => {
|
||||
include_str!("../../horizon-client/assets/horizon/lang/sq_al.json")
|
||||
}
|
||||
"assets/horizon/lang/cy_gb.json" => {
|
||||
include_str!("../../horizon-client/assets/horizon/lang/cy_gb.json")
|
||||
}
|
||||
"assets/horizon/lang/ga_ie.json" => {
|
||||
include_str!("../../horizon-client/assets/horizon/lang/ga_ie.json")
|
||||
}
|
||||
"assets/horizon/lang/eu_es.json" => {
|
||||
include_str!("../../horizon-client/assets/horizon/lang/eu_es.json")
|
||||
}
|
||||
"assets/horizon/lang/gl_es.json" => {
|
||||
include_str!("../../horizon-client/assets/horizon/lang/gl_es.json")
|
||||
}
|
||||
"assets/horizon/lang/fil_ph.json" => {
|
||||
include_str!("../../horizon-client/assets/horizon/lang/fil_ph.json")
|
||||
}
|
||||
"assets/horizon/lang/ta_in.json" => {
|
||||
include_str!("../../horizon-client/assets/horizon/lang/ta_in.json")
|
||||
}
|
||||
"assets/horizon/lang/mn_mn.json" => {
|
||||
include_str!("../../horizon-client/assets/horizon/lang/mn_mn.json")
|
||||
}
|
||||
"assets/horizon/lang/lo_la.json" => {
|
||||
include_str!("../../horizon-client/assets/horizon/lang/lo_la.json")
|
||||
}
|
||||
"assets/horizon/lang/so_so.json" => {
|
||||
include_str!("../../horizon-client/assets/horizon/lang/so_so.json")
|
||||
}
|
||||
"assets/horizon/lang/fy_nl.json" => {
|
||||
include_str!("../../horizon-client/assets/horizon/lang/fy_nl.json")
|
||||
}
|
||||
"assets/horizon/lang/gd_gb.json" => {
|
||||
include_str!("../../horizon-client/assets/horizon/lang/gd_gb.json")
|
||||
}
|
||||
"assets/horizon/lang/lb_lu.json" => {
|
||||
include_str!("../../horizon-client/assets/horizon/lang/lb_lu.json")
|
||||
}
|
||||
"assets/horizon/lang/ky_kg.json" => {
|
||||
include_str!("../../horizon-client/assets/horizon/lang/ky_kg.json")
|
||||
}
|
||||
"assets/horizon/lang/kn_in.json" => {
|
||||
include_str!("../../horizon-client/assets/horizon/lang/kn_in.json")
|
||||
}
|
||||
"assets/horizon/lang/mt_mt.json" => {
|
||||
include_str!("../../horizon-client/assets/horizon/lang/mt_mt.json")
|
||||
}
|
||||
"assets/horizon/lang/eo_uy.json" => {
|
||||
include_str!("../../horizon-client/assets/horizon/lang/eo_uy.json")
|
||||
}
|
||||
"assets/horizon/lang/haw_us.json" => {
|
||||
include_str!("../../horizon-client/assets/horizon/lang/haw_us.json")
|
||||
}
|
||||
"assets/horizon/lang/ig_ng.json" => {
|
||||
include_str!("../../horizon-client/assets/horizon/lang/ig_ng.json")
|
||||
}
|
||||
"assets/horizon/lang/la_la.json" => {
|
||||
include_str!("../../horizon-client/assets/horizon/lang/la_la.json")
|
||||
}
|
||||
"assets/horizon/lang/tt_ru.json" => {
|
||||
include_str!("../../horizon-client/assets/horizon/lang/tt_ru.json")
|
||||
}
|
||||
"assets/horizon/lang/yi_de.json" => {
|
||||
include_str!("../../horizon-client/assets/horizon/lang/yi_de.json")
|
||||
}
|
||||
"assets/horizon/lang/yo_ng.json" => {
|
||||
include_str!("../../horizon-client/assets/horizon/lang/yo_ng.json")
|
||||
}
|
||||
"assets/horizon/lang/ba_ru.json" => {
|
||||
include_str!("../../horizon-client/assets/horizon/lang/ba_ru.json")
|
||||
}
|
||||
"assets/horizon/lang/br_fr.json" => {
|
||||
include_str!("../../horizon-client/assets/horizon/lang/br_fr.json")
|
||||
}
|
||||
"assets/horizon/lang/cv_cu.json" => {
|
||||
include_str!("../../horizon-client/assets/horizon/lang/cv_cu.json")
|
||||
}
|
||||
"assets/horizon/lang/fo_fo.json" => {
|
||||
include_str!("../../horizon-client/assets/horizon/lang/fo_fo.json")
|
||||
}
|
||||
"assets/horizon/lang/fur_it.json" => {
|
||||
include_str!("../../horizon-client/assets/horizon/lang/fur_it.json")
|
||||
}
|
||||
"assets/horizon/lang/li_li.json" => {
|
||||
include_str!("../../horizon-client/assets/horizon/lang/li_li.json")
|
||||
}
|
||||
"assets/horizon/lang/lmo.json" => {
|
||||
include_str!("../../horizon-client/assets/horizon/lang/lmo.json")
|
||||
}
|
||||
"assets/horizon/lang/oc_fr.json" => {
|
||||
include_str!("../../horizon-client/assets/horizon/lang/oc_fr.json")
|
||||
}
|
||||
"assets/horizon/lang/sah_sah.json" => {
|
||||
include_str!("../../horizon-client/assets/horizon/lang/sah_sah.json")
|
||||
}
|
||||
"assets/horizon/lang/se_no.json" => {
|
||||
include_str!("../../horizon-client/assets/horizon/lang/se_no.json")
|
||||
}
|
||||
"assets/horizon/lang/szl.json" => {
|
||||
include_str!("../../horizon-client/assets/horizon/lang/szl.json")
|
||||
}
|
||||
"assets/horizon/lang/vec_it.json" => {
|
||||
include_str!("../../horizon-client/assets/horizon/lang/vec_it.json")
|
||||
}
|
||||
"assets/horizon/lang/de_de.json" | "assets/horizon/lang/de_at.json" => {
|
||||
include_str!("../../horizon-client/assets/horizon/lang/de_de.json")
|
||||
}
|
||||
|
||||
@@ -79,28 +79,65 @@ fn elements(tag: &Tag) -> Option<Vec<Tag>> {
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
fn number(t: &Tag) -> Option<i64> {
|
||||
match t {
|
||||
Tag::Byte(v) => Some(i64::from(*v)),
|
||||
Tag::Short(v) => Some(i64::from(*v)),
|
||||
Tag::Int(v) => Some(i64::from(*v)),
|
||||
Tag::Long(v) => Some(*v),
|
||||
_ => None,
|
||||
/// `DoubleTag.intValue` / `FloatTag.intValue` floor before the i32 conversion;
|
||||
/// integral tags use their intValue narrowing. Byte arrays then keep the low byte.
|
||||
fn int_value(t: &Tag) -> Option<i32> {
|
||||
Some(match t {
|
||||
Tag::Byte(v) => i32::from(*v),
|
||||
Tag::Short(v) => i32::from(*v),
|
||||
Tag::Int(v) => *v,
|
||||
Tag::Long(v) => *v as i32,
|
||||
Tag::Float(v) => f32::from_bits(*v).floor() as i32,
|
||||
Tag::Double(v) => f64::from_bits(*v).floor() as i32,
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
/// `FloatTag.longValue` truncates; `DoubleTag.longValue` floors before narrowing.
|
||||
fn long_value(t: &Tag) -> Option<i64> {
|
||||
Some(match t {
|
||||
Tag::Byte(v) => i64::from(*v),
|
||||
Tag::Short(v) => i64::from(*v),
|
||||
Tag::Int(v) => i64::from(*v),
|
||||
Tag::Long(v) => *v,
|
||||
// FloatTag.longValue truncates; DoubleTag.longValue floors first.
|
||||
Tag::Float(v) => f32::from_bits(*v) as i64,
|
||||
Tag::Double(v) => f64::from_bits(*v).floor() as i64,
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
#[derive(Clone, Copy)]
|
||||
enum ElementKind {
|
||||
List,
|
||||
NumericArray,
|
||||
}
|
||||
impl ElementKind {
|
||||
// Admission only: arrays require NumericTag; lists accept every tag type.
|
||||
fn accepts(self, value: &Tag) -> bool {
|
||||
matches!(self, Self::List)
|
||||
|| matches!(
|
||||
value,
|
||||
Tag::Byte(_)
|
||||
| Tag::Short(_)
|
||||
| Tag::Int(_)
|
||||
| Tag::Long(_)
|
||||
| Tag::Float(_)
|
||||
| Tag::Double(_)
|
||||
)
|
||||
}
|
||||
}
|
||||
/// Run `f` over the elements of a list/array, writing array results back.
|
||||
/// Rust view adapter: run `f` over the elements, then write arrays using their numeric accessor.
|
||||
/// None when `tag` is not list-like.
|
||||
fn with_elements<R>(tag: &mut Tag, f: impl FnOnce(&mut Vec<Tag>) -> R) -> Option<R> {
|
||||
fn with_elements<R>(tag: &mut Tag, f: impl FnOnce(&mut Vec<Tag>, ElementKind) -> R) -> Option<R> {
|
||||
match tag {
|
||||
Tag::List(l) => Some(f(l)),
|
||||
Tag::List(l) => Some(f(l, ElementKind::List)),
|
||||
Tag::ByteArray(_) | Tag::IntArray(_) | Tag::LongArray(_) => {
|
||||
let mut v = elements(tag)?;
|
||||
let r = f(&mut v);
|
||||
let nums: Vec<i64> = v.iter().filter_map(number).collect();
|
||||
let r = f(&mut v, ElementKind::NumericArray);
|
||||
match tag {
|
||||
Tag::ByteArray(a) => *a = nums.iter().map(|n| *n as u8).collect(),
|
||||
Tag::IntArray(a) => *a = nums.iter().map(|n| *n as i32).collect(),
|
||||
Tag::LongArray(a) => *a = nums,
|
||||
// Float/double byteValue uses intValue's floor, then narrows.
|
||||
Tag::ByteArray(a) => *a = v.iter().filter_map(int_value).map(|n| n as u8).collect(),
|
||||
Tag::IntArray(a) => *a = v.iter().filter_map(int_value).collect(),
|
||||
Tag::LongArray(a) => *a = v.iter().filter_map(long_value).collect(),
|
||||
_ => {}
|
||||
}
|
||||
Some(r)
|
||||
@@ -349,7 +386,7 @@ impl NbtPath {
|
||||
});
|
||||
removed
|
||||
}
|
||||
/// `insert` (also append and prepend): into every list the path reaches.
|
||||
/// `NbtPathArgument.NbtPath.insert`: insert accepted tags into every reached collection.
|
||||
pub fn insert(
|
||||
&self,
|
||||
index: i32,
|
||||
@@ -372,19 +409,23 @@ impl NbtPath {
|
||||
return;
|
||||
}
|
||||
let shown = crate::snbt::to_snbt(target);
|
||||
let result = with_elements(target, |list| {
|
||||
let result = with_elements(target, |list, kind| {
|
||||
let start = if index < 0 {
|
||||
list.len() as i64 + i64::from(index) + 1
|
||||
} else {
|
||||
i64::from(index)
|
||||
};
|
||||
let mut any = false;
|
||||
for (n, v) in values.iter().enumerate() {
|
||||
let at = start + n as i64;
|
||||
let mut at = start;
|
||||
for v in values {
|
||||
if !kind.accepts(v) {
|
||||
continue;
|
||||
}
|
||||
if at < 0 || at as usize > list.len() {
|
||||
return Err(CollectionError::InvalidIndex(at as i32));
|
||||
}
|
||||
list.insert(at as usize, v.clone());
|
||||
at += 1;
|
||||
any = true;
|
||||
}
|
||||
Ok(any)
|
||||
@@ -428,7 +469,8 @@ fn preferred_parent(node: &Node) -> Tag {
|
||||
_ => Tag::Compound(Compound::new()),
|
||||
}
|
||||
}
|
||||
/// `getOrCreateTag` (or `getTag` without `create`): the children of `parent`.
|
||||
/// Children of `parent`; the array creation arm follows
|
||||
/// `NbtPathArgument.AllElementsNode.getOrCreateTag` admission.
|
||||
fn step_mut(
|
||||
node: &Node,
|
||||
parent: &mut Tag,
|
||||
@@ -468,11 +510,14 @@ fn step_mut(
|
||||
}
|
||||
Node::AllElements => {
|
||||
let make = create;
|
||||
let _ = with_elements(parent, |list| {
|
||||
let _ = with_elements(parent, |list, kind| {
|
||||
if list.is_empty() {
|
||||
if let Some(make) = make {
|
||||
list.push(make());
|
||||
out(&mut list[0]);
|
||||
let value = make();
|
||||
if kind.accepts(&value) {
|
||||
list.push(value);
|
||||
out(&mut list[0]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for t in list.iter_mut() {
|
||||
@@ -482,7 +527,7 @@ fn step_mut(
|
||||
});
|
||||
}
|
||||
Node::Index(i) => {
|
||||
let _ = with_elements(parent, |list| {
|
||||
let _ = with_elements(parent, |list, _kind| {
|
||||
let n = list.len() as i64;
|
||||
let idx = if *i < 0 {
|
||||
n + i64::from(*i)
|
||||
@@ -518,7 +563,8 @@ fn step_mut(
|
||||
}
|
||||
}
|
||||
}
|
||||
/// `Node.setTag`: replace the child(ren) of `parent` with `value`.
|
||||
/// Element setters follow `NbtPathArgument.AllElementsNode.setTag` and
|
||||
/// `NbtPathArgument.IndexedElementNode.setTag`; object nodes replace their children.
|
||||
fn set_tag(node: &Node, parent: &mut Tag, value: &Tag) -> usize {
|
||||
match node {
|
||||
Node::Child(name) => {
|
||||
@@ -538,29 +584,36 @@ fn set_tag(node: &Node, parent: &mut Tag, value: &Tag) -> usize {
|
||||
}
|
||||
0
|
||||
}
|
||||
Node::AllElements => with_elements(parent, |list| {
|
||||
if list.is_empty() {
|
||||
list.push(value.clone());
|
||||
Node::AllElements => with_elements(parent, |list, kind| {
|
||||
let len = list.len();
|
||||
if len == 0 {
|
||||
if kind.accepts(value) {
|
||||
list.push(value.clone());
|
||||
}
|
||||
// AllElementsNode returns 1 here even when addTag rejects.
|
||||
return 1;
|
||||
}
|
||||
// Compare the original tags, before numeric conversion.
|
||||
let changed = list.iter().filter(|t| *t != value).count();
|
||||
if changed == 0 {
|
||||
return 0;
|
||||
}
|
||||
for t in list.iter_mut() {
|
||||
*t = value.clone();
|
||||
list.clear();
|
||||
if !kind.accepts(value) {
|
||||
return 0;
|
||||
}
|
||||
list.resize(len, value.clone());
|
||||
changed
|
||||
})
|
||||
.unwrap_or(0),
|
||||
Node::Index(i) => with_elements(parent, |list| {
|
||||
Node::Index(i) => with_elements(parent, |list, kind| {
|
||||
let n = list.len() as i64;
|
||||
let idx = if *i < 0 {
|
||||
n + i64::from(*i)
|
||||
} else {
|
||||
i64::from(*i)
|
||||
};
|
||||
if (0..n).contains(&idx) && list[idx as usize] != *value {
|
||||
if (0..n).contains(&idx) && list[idx as usize] != *value && kind.accepts(value) {
|
||||
list[idx as usize] = value.clone();
|
||||
1
|
||||
} else {
|
||||
@@ -586,6 +639,7 @@ fn set_tag(node: &Node, parent: &mut Tag, value: &Tag) -> usize {
|
||||
Node::MatchRoot(_) => 0,
|
||||
}
|
||||
}
|
||||
/// Removal arms, including `NbtPathArgument.AllElementsNode.removeTag`.
|
||||
fn remove_tag(node: &Node, parent: &mut Tag) -> usize {
|
||||
match node {
|
||||
Node::Child(name) => match parent {
|
||||
@@ -603,13 +657,13 @@ fn remove_tag(node: &Node, parent: &mut Tag) -> usize {
|
||||
}
|
||||
_ => 0,
|
||||
},
|
||||
Node::AllElements => with_elements(parent, |l| {
|
||||
Node::AllElements => with_elements(parent, |l, _kind| {
|
||||
let n = l.len();
|
||||
l.clear();
|
||||
n
|
||||
})
|
||||
.unwrap_or(0),
|
||||
Node::Index(i) => with_elements(parent, |l| {
|
||||
Node::Index(i) => with_elements(parent, |l, _kind| {
|
||||
let n = l.len() as i64;
|
||||
let idx = if *i < 0 {
|
||||
n + i64::from(*i)
|
||||
@@ -887,6 +941,100 @@ mod tests {
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn numeric_array_edits_use_the_destination_numeric_accessor() {
|
||||
for (initial, value, inserted, indexed, all) in [
|
||||
(
|
||||
"{v:[B;1b,2b]}",
|
||||
"-3.5f",
|
||||
"{v:[B;1b,-4b,2b]}",
|
||||
"{v:[B;-4b,2b]}",
|
||||
"{v:[B;-4b,-4b]}",
|
||||
),
|
||||
(
|
||||
"{v:[B;1b,2b]}",
|
||||
"-3.5d",
|
||||
"{v:[B;1b,-4b,2b]}",
|
||||
"{v:[B;-4b,2b]}",
|
||||
"{v:[B;-4b,-4b]}",
|
||||
),
|
||||
(
|
||||
"{v:[I;1,2]}",
|
||||
"-3.5f",
|
||||
"{v:[I;1,-4,2]}",
|
||||
"{v:[I;-4,2]}",
|
||||
"{v:[I;-4,-4]}",
|
||||
),
|
||||
(
|
||||
"{v:[I;1,2]}",
|
||||
"-3.5d",
|
||||
"{v:[I;1,-4,2]}",
|
||||
"{v:[I;-4,2]}",
|
||||
"{v:[I;-4,-4]}",
|
||||
),
|
||||
(
|
||||
"{v:[L;1L,2L]}",
|
||||
"-3.5f",
|
||||
"{v:[L;1L,-3L,2L]}",
|
||||
"{v:[L;-3L,2L]}",
|
||||
"{v:[L;-3L,-3L]}",
|
||||
),
|
||||
(
|
||||
"{v:[L;1L,2L]}",
|
||||
"-3.5d",
|
||||
"{v:[L;1L,-4L,2L]}",
|
||||
"{v:[L;-4L,2L]}",
|
||||
"{v:[L;-4L,-4L]}",
|
||||
),
|
||||
] {
|
||||
let value = tag(value);
|
||||
let mut root = tag(initial);
|
||||
assert_eq!(
|
||||
path("v")
|
||||
.insert(1, &mut root, std::slice::from_ref(&value))
|
||||
.unwrap(),
|
||||
1
|
||||
);
|
||||
assert_eq!(root, tag(inserted));
|
||||
let mut root = tag(initial);
|
||||
assert_eq!(path("v[0]").set(&mut root, &value).unwrap(), 1);
|
||||
assert_eq!(root, tag(indexed));
|
||||
let mut root = tag(initial);
|
||||
assert_eq!(path("v[]").set(&mut root, &value).unwrap(), 2);
|
||||
assert_eq!(root, tag(all));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn numeric_arrays_reject_nonnumeric_insert_and_indexed_set() {
|
||||
for initial in ["{v:[B;1b,2b]}", "{v:[I;1,2]}", "{v:[L;1L,2L]}"] {
|
||||
let original = tag(initial);
|
||||
let value = tag("\"bad\"");
|
||||
for index in [0, 99, -99] {
|
||||
let mut root = original.clone();
|
||||
assert_eq!(
|
||||
path("v")
|
||||
.insert(index, &mut root, std::slice::from_ref(&value))
|
||||
.unwrap(),
|
||||
0
|
||||
);
|
||||
assert_eq!(root, original);
|
||||
}
|
||||
let mut root = original.clone();
|
||||
assert_eq!(path("v[0]").set(&mut root, &value).unwrap(), 0);
|
||||
assert_eq!(root, original);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty_array_wildcard_set_preserves_vanillas_count_on_rejection() {
|
||||
for initial in ["{v:[B;]}", "{v:[I;]}", "{v:[L;]}"] {
|
||||
let mut root = tag(initial);
|
||||
assert_eq!(path("v[]").set(&mut root, &tag("\"bad\"")).unwrap(), 1);
|
||||
assert_eq!(root, tag(initial));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn partial_comparison() {
|
||||
let actual = tag("{a:1,b:{c:[1,2,3],d:\"x\"},e:2}");
|
||||
|
||||
@@ -173,6 +173,16 @@ impl Registries {
|
||||
fill(&mut self.templates, "templates");
|
||||
fill(&mut self.persistent_components, "persistent_components");
|
||||
fill(&mut self.learnable_recipes, "learnable_recipes");
|
||||
if self.summonable.is_empty() {
|
||||
self.summonable = strings(&r["summonable"]);
|
||||
self.summonable.sort();
|
||||
self.summonable.dedup();
|
||||
}
|
||||
if self.entity_types.is_empty() {
|
||||
self.entity_types = strings(&r["entity_types"]);
|
||||
self.entity_types.sort();
|
||||
self.entity_types.dedup();
|
||||
}
|
||||
const RELOADED: [&str; 5] = [
|
||||
"minecraft:advancement",
|
||||
"minecraft:recipe",
|
||||
@@ -236,6 +246,16 @@ impl Registries {
|
||||
fill(&mut self.templates, &e.templates);
|
||||
fill(&mut self.persistent_components, &e.persistent_components);
|
||||
fill(&mut self.learnable_recipes, &e.learnable_recipes);
|
||||
if self.summonable.is_empty() {
|
||||
self.summonable.clone_from(&e.summonable);
|
||||
self.summonable.sort();
|
||||
self.summonable.dedup();
|
||||
}
|
||||
if self.entity_types.is_empty() {
|
||||
self.entity_types.clone_from(&e.entity_types);
|
||||
self.entity_types.sort();
|
||||
self.entity_types.dedup();
|
||||
}
|
||||
for (name, ids) in &e.by_registry {
|
||||
if !self.by_registry.contains_key(name) {
|
||||
self.by_registry.insert(name.clone(), ids.clone());
|
||||
|
||||
@@ -179,12 +179,13 @@ impl PadState {
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct Edges {
|
||||
held: u32,
|
||||
suppressed: u32,
|
||||
}
|
||||
impl Edges {
|
||||
pub fn update(&mut self, state: &PadState, threshold: f32) -> Vec<(Button, bool)> {
|
||||
let mut now = state.buttons;
|
||||
for (trigger, button) in [(0, Button::LeftTrigger), (1, Button::RightTrigger)] {
|
||||
let was = self.held & button.bit() != 0;
|
||||
let was = (self.held | self.suppressed) & button.bit() != 0;
|
||||
let value = state.triggers[trigger];
|
||||
let on = if was {
|
||||
value >= (threshold - 0.1).max(0.05)
|
||||
@@ -197,6 +198,8 @@ impl Edges {
|
||||
now &= !button.bit();
|
||||
}
|
||||
}
|
||||
self.suppressed &= now;
|
||||
now &= !self.suppressed;
|
||||
let changed = now ^ self.held;
|
||||
self.held = now;
|
||||
Button::ALL
|
||||
@@ -217,6 +220,50 @@ impl Edges {
|
||||
pub fn is_held(&self, button: Button) -> bool {
|
||||
self.held & button.bit() != 0
|
||||
}
|
||||
/// Cancel a context without turning its still-held buttons into new presses.
|
||||
pub fn cancel(&mut self) -> Vec<(Button, bool)> {
|
||||
self.suppressed |= self.held;
|
||||
self.release_all()
|
||||
}
|
||||
}
|
||||
|
||||
/// Intentional activity may take input ownership; an unchanged hold may not.
|
||||
#[derive(Default)]
|
||||
pub struct Activity {
|
||||
buttons: u32,
|
||||
sticks: [[f32; 2]; 2],
|
||||
}
|
||||
impl Activity {
|
||||
pub fn observe(&mut self, state: &PadState, settings: &PadSettings) -> bool {
|
||||
let mut buttons = state.buttons;
|
||||
for (i, button) in [(0, Button::LeftTrigger), (1, Button::RightTrigger)] {
|
||||
let threshold = if self.buttons & button.bit() != 0 {
|
||||
(settings.trigger_threshold - 0.1).max(0.05)
|
||||
} else {
|
||||
settings.trigger_threshold
|
||||
};
|
||||
if state.triggers[i] >= threshold {
|
||||
buttons |= button.bit();
|
||||
}
|
||||
}
|
||||
let mut activity = buttons & !self.buttons != 0;
|
||||
self.buttons = buttons;
|
||||
for (i, (stick, deadzone)) in [
|
||||
(state.left, settings.move_deadzone),
|
||||
(state.right, settings.look_deadzone),
|
||||
]
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
{
|
||||
if length(stick) <= deadzone {
|
||||
self.sticks[i] = [0.0; 2];
|
||||
} else if length([stick[0] - self.sticks[i][0], stick[1] - self.sticks[i][1]]) > 0.08 {
|
||||
activity = true;
|
||||
self.sticks[i] = stick;
|
||||
}
|
||||
}
|
||||
activity
|
||||
}
|
||||
}
|
||||
|
||||
/// Horizon's pad-only actions (no vanilla key mapping).
|
||||
@@ -248,6 +295,39 @@ pub const ACTIONS: &[(&str, Option<Button>)] = &[
|
||||
("key.smoothCamera", None),
|
||||
];
|
||||
|
||||
/// How a bindable action reaches the game: one of its own handlers, shared
|
||||
/// with the keyboard where the keyboard has one, or else the vanilla default
|
||||
/// key or button of its mapping, as a rebound keyboard key would.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum Route {
|
||||
HotbarStep {
|
||||
next: bool,
|
||||
},
|
||||
/// Held, or flipped when the pad's toggle sneak is on.
|
||||
Sneak,
|
||||
Screenshot,
|
||||
SmoothCamera,
|
||||
Key(winit::keyboard::KeyCode),
|
||||
Mouse(winit::event::MouseButton),
|
||||
}
|
||||
|
||||
/// The route of a bindable action; `None` for one the pad can't reach.
|
||||
pub fn route(action: &str) -> Option<Route> {
|
||||
match action {
|
||||
HOTBAR_PREVIOUS => Some(Route::HotbarStep { next: false }),
|
||||
HOTBAR_NEXT => Some(Route::HotbarStep { next: true }),
|
||||
"key.sneak" => Some(Route::Sneak),
|
||||
"key.screenshot" => Some(Route::Screenshot),
|
||||
"key.smoothCamera" => Some(Route::SmoothCamera),
|
||||
_ => {
|
||||
let default = crate::keybinds::KeyBinds::default_of(action);
|
||||
crate::keybinds::mouse_button(default)
|
||||
.map(Route::Mouse)
|
||||
.or_else(|| crate::keybinds::key_code(default).map(Route::Key))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An action's name in the binds list: vanilla's translation key, or
|
||||
/// Horizon's own English for the pad-only actions.
|
||||
pub fn action_caption(action: &str) -> &str {
|
||||
@@ -313,31 +393,6 @@ impl GlyphStyle {
|
||||
}
|
||||
}
|
||||
|
||||
/// How a controller drives menus (docs/controllers.md, "Menus and
|
||||
/// inventories").
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
|
||||
pub enum MenuNav {
|
||||
/// A console-style highlight moved between widgets and slots.
|
||||
#[default]
|
||||
Focus,
|
||||
/// A virtual mouse pointer.
|
||||
Pointer,
|
||||
}
|
||||
impl MenuNav {
|
||||
pub fn name(self) -> &'static str {
|
||||
match self {
|
||||
MenuNav::Focus => "focus",
|
||||
MenuNav::Pointer => "pointer",
|
||||
}
|
||||
}
|
||||
pub fn parse(name: &str) -> Self {
|
||||
match name {
|
||||
"pointer" => MenuNav::Pointer,
|
||||
_ => MenuNav::Focus,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The on-screen keyboard A opens on a text field in focus mode.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
|
||||
pub enum TextKeyboard {
|
||||
@@ -399,9 +454,12 @@ pub struct PadSettings {
|
||||
/// holding it, unless vanilla's toggle crouch is on already.
|
||||
pub toggle_sneak: bool,
|
||||
pub glyphs: GlyphStyle,
|
||||
/// How the pad drives menus: a focus highlight or a virtual pointer.
|
||||
pub menu_nav: MenuNav,
|
||||
pub keyboard: TextKeyboard,
|
||||
/// Menu pointer multiplier, scroll lines/second, and repeat times in seconds.
|
||||
pub pointer_speed: f32,
|
||||
pub scroll_speed: f32,
|
||||
pub repeat_delay: f32,
|
||||
pub repeat_interval: f32,
|
||||
/// Action name -> button, `None` for unbound; missing means the default.
|
||||
bindings: BTreeMap<&'static str, Option<Button>>,
|
||||
}
|
||||
@@ -420,8 +478,11 @@ impl Default for PadSettings {
|
||||
trigger_threshold: 0.4,
|
||||
toggle_sneak: true,
|
||||
glyphs: GlyphStyle::Auto,
|
||||
menu_nav: MenuNav::Focus,
|
||||
keyboard: TextKeyboard::Auto,
|
||||
pointer_speed: 1.0,
|
||||
scroll_speed: 12.0,
|
||||
repeat_delay: 0.35,
|
||||
repeat_interval: 0.09,
|
||||
bindings: BTreeMap::new(),
|
||||
}
|
||||
}
|
||||
@@ -462,6 +523,13 @@ impl PadSettings {
|
||||
.filter(|v| v.is_finite())
|
||||
.map_or(d, |v| v.clamp(0.0, 1.0))
|
||||
};
|
||||
let bounded = |default: f32, min: f32, max: f32| {
|
||||
value
|
||||
.parse::<f32>()
|
||||
.ok()
|
||||
.filter(|v| v.is_finite())
|
||||
.map_or(default, |v| v.clamp(min, max))
|
||||
};
|
||||
match key.trim() {
|
||||
"enabled" => s.enabled = flag(s.enabled),
|
||||
"vibration" => s.vibration = flag(s.vibration),
|
||||
@@ -477,8 +545,11 @@ impl PadSettings {
|
||||
}
|
||||
"toggleSneak" => s.toggle_sneak = flag(s.toggle_sneak),
|
||||
"glyphs" => s.glyphs = GlyphStyle::parse(value),
|
||||
"menuNavigation" => s.menu_nav = MenuNav::parse(value),
|
||||
"keyboard" => s.keyboard = TextKeyboard::parse(value),
|
||||
"pointerSpeed" => s.pointer_speed = bounded(s.pointer_speed, 0.25, 3.0),
|
||||
"scrollSpeed" => s.scroll_speed = bounded(s.scroll_speed, 1.0, 36.0),
|
||||
"repeatDelay" => s.repeat_delay = bounded(s.repeat_delay, 0.1, 1.0),
|
||||
"repeatInterval" => s.repeat_interval = bounded(s.repeat_interval, 0.03, 0.3),
|
||||
other => {
|
||||
if let Some(action) = other.strip_prefix("bind_") {
|
||||
let button = if value == "none" {
|
||||
@@ -497,7 +568,7 @@ impl PadSettings {
|
||||
}
|
||||
pub fn serialize(&self) -> String {
|
||||
let mut text = format!(
|
||||
"enabled:{}\nvibration:{}\nadaptiveTriggers:{}\nlightbar:{}\nlookSensitivity:{}\ninvertX:{}\ninvertY:{}\nmoveDeadzone:{}\nlookDeadzone:{}\ntriggerThreshold:{}\ntoggleSneak:{}\nglyphs:{}\nmenuNavigation:{}\nkeyboard:{}\n",
|
||||
"enabled:{}\nvibration:{}\nadaptiveTriggers:{}\nlightbar:{}\nlookSensitivity:{}\ninvertX:{}\ninvertY:{}\nmoveDeadzone:{}\nlookDeadzone:{}\ntriggerThreshold:{}\ntoggleSneak:{}\nglyphs:{}\nkeyboard:{}\n",
|
||||
bool_text(self.enabled),
|
||||
bool_text(self.vibration),
|
||||
bool_text(self.adaptive_triggers),
|
||||
@@ -510,9 +581,12 @@ impl PadSettings {
|
||||
self.trigger_threshold,
|
||||
bool_text(self.toggle_sneak),
|
||||
self.glyphs.name(),
|
||||
self.menu_nav.name(),
|
||||
self.keyboard.name(),
|
||||
);
|
||||
text.push_str(&format!(
|
||||
"pointerSpeed:{}\nscrollSpeed:{}\nrepeatDelay:{}\nrepeatInterval:{}\n",
|
||||
self.pointer_speed, self.scroll_speed, self.repeat_delay, self.repeat_interval,
|
||||
));
|
||||
for (action, button) in &self.bindings {
|
||||
text.push_str(&format!(
|
||||
"bind_{action}:{}\n",
|
||||
@@ -1163,6 +1237,131 @@ pub fn bow_power(ticks: u32) -> f32 {
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn every_bindable_action_reaches_the_game() {
|
||||
for (action, _) in ACTIONS {
|
||||
assert!(route(action).is_some(), "{action} has nowhere to go");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn navigation_preferences_migrate_and_stay_with_each_player() {
|
||||
let dir = std::env::temp_dir().join(format!(
|
||||
"horizon-pad-{}-{}",
|
||||
std::process::id(),
|
||||
std::time::SystemTime::now()
|
||||
.duration_since(std::time::UNIX_EPOCH)
|
||||
.unwrap()
|
||||
.as_nanos()
|
||||
));
|
||||
let p2 = dir.join("P2");
|
||||
fs::create_dir_all(&p2).unwrap();
|
||||
let fresh = PadSettings::load(&dir);
|
||||
assert_eq!(fresh, PadSettings::default());
|
||||
// An older file, with the removed menuNavigation key: bindings kept.
|
||||
let legacy =
|
||||
PadSettings::parse("menuNavigation:pointer\nbind_key.jump:east\nlookSensitivity:0.7\n");
|
||||
assert_eq!(legacy.binding("key.jump"), Some(Button::East));
|
||||
assert_eq!(legacy.look_sensitivity, 0.7);
|
||||
fresh.save(&dir);
|
||||
assert!(!dir.join(FILE).exists(), "defaults write no file");
|
||||
let mut other = legacy;
|
||||
other.pointer_speed = 2.5;
|
||||
other.scroll_speed = 24.0;
|
||||
other.repeat_delay = 0.6;
|
||||
other.repeat_interval = 0.12;
|
||||
other.save(&p2);
|
||||
assert_eq!(PadSettings::load(&p2), other);
|
||||
assert_eq!(PadSettings::load(&dir), fresh, "P2 did not write P1");
|
||||
let invalid = PadSettings::parse(
|
||||
"pointerSpeed:NaN\nscrollSpeed:inf\nrepeatDelay:-10\nrepeatInterval:20\n",
|
||||
);
|
||||
assert_eq!((invalid.pointer_speed, invalid.scroll_speed), (1.0, 12.0));
|
||||
assert_eq!((invalid.repeat_delay, invalid.repeat_interval), (0.1, 0.3));
|
||||
let bounded = PadSettings::parse(
|
||||
"pointerSpeed:10\nscrollSpeed:-1\nrepeatDelay:NaN\nrepeatInterval:inf\n",
|
||||
);
|
||||
assert_eq!((bounded.pointer_speed, bounded.scroll_speed), (3.0, 1.0));
|
||||
assert_eq!(
|
||||
(bounded.repeat_delay, bounded.repeat_interval),
|
||||
(0.35, 0.09)
|
||||
);
|
||||
fs::remove_dir_all(dir).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ownership_requires_new_activity_and_ignores_drift() {
|
||||
let settings = PadSettings::default();
|
||||
let mut p1 = Activity::default();
|
||||
let mut p2 = Activity::default();
|
||||
let mut state = PadState {
|
||||
left: [0.04, 0.03],
|
||||
..PadState::default()
|
||||
};
|
||||
assert!(!p1.observe(&state, &settings));
|
||||
state.set(Button::South, true);
|
||||
assert!(p1.observe(&state, &settings));
|
||||
assert!(
|
||||
!p1.observe(&state, &settings),
|
||||
"held pad cannot reclaim mouse ownership"
|
||||
);
|
||||
assert!(
|
||||
p2.observe(&state, &settings),
|
||||
"another player's tracker is independent"
|
||||
);
|
||||
state.set(Button::South, false);
|
||||
assert!(!p1.observe(&state, &settings));
|
||||
state.left = [0.5, 0.0];
|
||||
assert!(p1.observe(&state, &settings));
|
||||
state.left = [0.52, 0.0];
|
||||
assert!(!p1.observe(&state, &settings));
|
||||
for x in [0.54, 0.56] {
|
||||
state.left = [x, 0.0];
|
||||
assert!(!p1.observe(&state, &settings));
|
||||
}
|
||||
state.left = [0.6, 0.0];
|
||||
assert!(
|
||||
p1.observe(&state, &settings),
|
||||
"slow intentional movement accumulates"
|
||||
);
|
||||
state.left = [0.0; 2];
|
||||
state.triggers[0] = 0.5;
|
||||
assert!(p1.observe(&state, &settings));
|
||||
state.triggers[0] = 0.35;
|
||||
assert!(!p1.observe(&state, &settings));
|
||||
state.triggers[0] = 0.45;
|
||||
assert!(
|
||||
!p1.observe(&state, &settings),
|
||||
"trigger threshold noise is not new activity"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cancelled_holds_stay_released_until_neutral_then_press_again() {
|
||||
let mut edges = Edges::default();
|
||||
let mut state = PadState::default();
|
||||
state.set(Button::South, true);
|
||||
state.triggers[1] = 0.8;
|
||||
assert_eq!(
|
||||
edges.update(&state, 0.4),
|
||||
vec![(Button::South, true), (Button::RightTrigger, true)]
|
||||
);
|
||||
assert_eq!(
|
||||
edges.cancel(),
|
||||
vec![(Button::South, false), (Button::RightTrigger, false)]
|
||||
);
|
||||
assert!(edges.update(&state, 0.4).is_empty());
|
||||
state.triggers[1] = 0.35;
|
||||
assert!(edges.update(&state, 0.4).is_empty());
|
||||
assert!(edges.update(&PadState::default(), 0.4).is_empty());
|
||||
assert_eq!(edges.update(&state, 0.4), vec![(Button::South, true)]);
|
||||
state.triggers[1] = 0.7;
|
||||
assert_eq!(
|
||||
edges.update(&state, 0.4),
|
||||
vec![(Button::RightTrigger, true)]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn defaults_follow_bedrock() {
|
||||
let s = PadSettings::default();
|
||||
@@ -1414,14 +1613,13 @@ mod tests {
|
||||
assert_eq!(stick_direction([0.9, 0.2], 0.5), Some(Button::DPadRight));
|
||||
assert_eq!(stick_direction([-0.2, -0.8], 0.5), Some(Button::DPadDown));
|
||||
assert_eq!(stick_direction([0.3, 0.3], 0.5), None);
|
||||
let mut s = PadSettings::default();
|
||||
assert_eq!(s.menu_nav, MenuNav::Focus);
|
||||
s.menu_nav = MenuNav::Pointer;
|
||||
s.keyboard = TextKeyboard::Horizon;
|
||||
let back = PadSettings::parse(&s.serialize());
|
||||
let s = PadSettings {
|
||||
keyboard: TextKeyboard::Horizon,
|
||||
..PadSettings::default()
|
||||
};
|
||||
assert_eq!(
|
||||
(back.menu_nav, back.keyboard),
|
||||
(MenuNav::Pointer, TextKeyboard::Horizon)
|
||||
PadSettings::parse(&s.serialize()).keyboard,
|
||||
TextKeyboard::Horizon
|
||||
);
|
||||
assert!(steam_keyboard(TextKeyboard::Steam) && !steam_keyboard(TextKeyboard::Horizon));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
//! The keys a player's mappings hold, as their vanilla default keys, and which
|
||||
//! devices hold each one. A key stays held while any device holds it, so one
|
||||
//! device letting go (splitscreen moving the keyboard to another player, say)
|
||||
//! can't release what another still presses.
|
||||
|
||||
use std::collections::HashMap;
|
||||
use winit::keyboard::KeyCode;
|
||||
|
||||
/// Where a press came from.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum Source {
|
||||
/// The keyboard and mouse, and the scripting socket acting as them.
|
||||
Keyboard,
|
||||
Pad,
|
||||
}
|
||||
|
||||
impl Source {
|
||||
fn bit(self) -> u8 {
|
||||
match self {
|
||||
Source::Keyboard => 1,
|
||||
Source::Pad => 2,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, Eq)]
|
||||
pub struct HeldKeys {
|
||||
held: HashMap<KeyCode, u8>,
|
||||
}
|
||||
|
||||
impl HeldKeys {
|
||||
pub fn contains(&self, key: &KeyCode) -> bool {
|
||||
self.held.contains_key(key)
|
||||
}
|
||||
/// `source` holds `key`. True when nothing held it before.
|
||||
pub fn press(&mut self, key: KeyCode, source: Source) -> bool {
|
||||
let sources = self.held.entry(key).or_insert(0);
|
||||
let new = *sources == 0;
|
||||
*sources |= source.bit();
|
||||
new
|
||||
}
|
||||
/// `source` lets go of `key`. True when nothing holds it any more.
|
||||
pub fn release(&mut self, key: &KeyCode, source: Source) -> bool {
|
||||
let Some(sources) = self.held.get_mut(key) else {
|
||||
return true;
|
||||
};
|
||||
*sources &= !source.bit();
|
||||
if *sources == 0 {
|
||||
self.held.remove(key);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
pub fn held_by(&self, key: &KeyCode, source: Source) -> bool {
|
||||
self.held
|
||||
.get(key)
|
||||
.is_some_and(|sources| sources & source.bit() != 0)
|
||||
}
|
||||
/// `source` lets go of everything: the keys nothing holds any more.
|
||||
pub fn release_source(&mut self, source: Source) -> Vec<KeyCode> {
|
||||
let keys: Vec<KeyCode> = self
|
||||
.held
|
||||
.iter()
|
||||
.filter(|(_, sources)| *sources & source.bit() != 0)
|
||||
.map(|(key, _)| *key)
|
||||
.collect();
|
||||
keys.into_iter()
|
||||
.filter(|key| self.release(key, source))
|
||||
.collect()
|
||||
}
|
||||
/// Held, by the keyboard unless a device already holds it: for callers
|
||||
/// that don't say where the press came from.
|
||||
pub fn insert(&mut self, key: KeyCode) -> bool {
|
||||
if self.contains(&key) {
|
||||
return false;
|
||||
}
|
||||
self.press(key, Source::Keyboard)
|
||||
}
|
||||
/// Let go of `key` whoever holds it.
|
||||
pub fn remove(&mut self, key: &KeyCode) -> bool {
|
||||
self.held.remove(key).is_some()
|
||||
}
|
||||
pub fn clear(&mut self) {
|
||||
self.held.clear();
|
||||
}
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.held.is_empty()
|
||||
}
|
||||
pub fn len(&self) -> usize {
|
||||
self.held.len()
|
||||
}
|
||||
pub fn iter(&self) -> impl Iterator<Item = &KeyCode> {
|
||||
self.held.keys()
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoIterator for HeldKeys {
|
||||
type Item = KeyCode;
|
||||
type IntoIter = std::collections::hash_map::IntoKeys<KeyCode, u8>;
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.held.into_keys()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoIterator for &'a HeldKeys {
|
||||
type Item = &'a KeyCode;
|
||||
type IntoIter = std::collections::hash_map::Keys<'a, KeyCode, u8>;
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.held.keys()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromIterator<KeyCode> for HeldKeys {
|
||||
fn from_iter<I: IntoIterator<Item = KeyCode>>(keys: I) -> Self {
|
||||
let mut held = HeldKeys::default();
|
||||
for key in keys {
|
||||
held.insert(key);
|
||||
}
|
||||
held
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn a_key_stays_held_while_any_device_holds_it() {
|
||||
let mut keys = HeldKeys::default();
|
||||
assert!(keys.press(KeyCode::Space, Source::Pad));
|
||||
assert!(!keys.press(KeyCode::Space, Source::Keyboard));
|
||||
assert!(keys.press(KeyCode::KeyW, Source::Keyboard));
|
||||
assert_eq!(keys.release_source(Source::Keyboard), vec![KeyCode::KeyW]);
|
||||
assert!(keys.contains(&KeyCode::Space) && !keys.contains(&KeyCode::KeyW));
|
||||
assert!(keys.held_by(&KeyCode::Space, Source::Pad));
|
||||
assert!(!keys.held_by(&KeyCode::Space, Source::Keyboard));
|
||||
assert!(keys.release(&KeyCode::Space, Source::Pad));
|
||||
assert!(keys.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn untagged_inserts_and_removes_act_as_before() {
|
||||
let mut keys = HeldKeys::default();
|
||||
keys.press(KeyCode::ShiftLeft, Source::Pad);
|
||||
assert!(!keys.insert(KeyCode::ShiftLeft), "already held");
|
||||
assert!(!keys.held_by(&KeyCode::ShiftLeft, Source::Keyboard));
|
||||
assert!(
|
||||
keys.remove(&KeyCode::ShiftLeft),
|
||||
"remove lets go for everyone"
|
||||
);
|
||||
assert!(!keys.contains(&KeyCode::ShiftLeft));
|
||||
assert!(keys.release(&KeyCode::KeyA, Source::Keyboard), "never held");
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@
|
||||
#![forbid(unsafe_code)]
|
||||
pub mod clipboard;
|
||||
pub mod gamepad;
|
||||
pub mod held;
|
||||
pub mod input;
|
||||
pub mod interaction_input;
|
||||
pub mod key_names;
|
||||
@@ -12,4 +13,5 @@ pub mod keybinds;
|
||||
pub mod keymapping;
|
||||
pub mod modifiers;
|
||||
pub mod mouse;
|
||||
pub mod snap;
|
||||
pub mod window;
|
||||
@@ -0,0 +1,152 @@
|
||||
//! Where the controller's menu cursor settles once the stick is let go, and
|
||||
//! how it gets there. Every rule's number lives in [`Tuning`], so the feel can
|
||||
//! be adjusted in one place.
|
||||
|
||||
/// The snapping engine's knobs, in GUI pixels and seconds.
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub struct Tuning {
|
||||
/// A let-go cursor settles on a target this close to it.
|
||||
pub radius: f32,
|
||||
/// How long the glide onto a target takes.
|
||||
pub glide_seconds: f32,
|
||||
/// Movement shorter than this is a wobble: the cursor stays where it was.
|
||||
pub min_travel: f32,
|
||||
/// A flick that ends still nearest its starting target commits to the
|
||||
/// neighbour it was heading for once it covered this fraction of the way.
|
||||
pub commit: f32,
|
||||
/// How far off the flick's direction a neighbour may lie (cosine of the
|
||||
/// angle: 0.7 is about 45 degrees).
|
||||
pub cone: f32,
|
||||
/// The pointer's speed over a slot or control, as a fraction of its
|
||||
/// speed elsewhere (1 leaves it unchanged).
|
||||
pub over_target_speed: f32,
|
||||
}
|
||||
|
||||
pub const TUNING: Tuning = Tuning {
|
||||
radius: 16.0,
|
||||
glide_seconds: 0.025,
|
||||
min_travel: 1.5,
|
||||
commit: 0.15,
|
||||
cone: 0.7,
|
||||
over_target_speed: 1.0,
|
||||
};
|
||||
|
||||
type Point = (f32, f32);
|
||||
|
||||
fn distance(a: Point, b: Point) -> f32 {
|
||||
((a.0 - b.0).powi(2) + (a.1 - b.1).powi(2)).sqrt()
|
||||
}
|
||||
|
||||
/// The target nearest `at`, if one lies within `radius`.
|
||||
pub fn nearest(at: Point, targets: &[Point], radius: f32) -> Option<usize> {
|
||||
targets
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, t)| (i, distance(at, *t)))
|
||||
.filter(|(_, d)| *d <= radius)
|
||||
.min_by(|a, b| a.1.total_cmp(&b.1))
|
||||
.map(|(i, _)| i)
|
||||
}
|
||||
|
||||
/// Where a stick movement from `start` to `end` settles among `targets`
|
||||
/// (their centres), or `None` to leave the cursor where it is.
|
||||
pub fn settle(start: Point, end: Point, targets: &[Point], tuning: &Tuning) -> Option<usize> {
|
||||
let near = nearest(end, targets, tuning.radius);
|
||||
let travel = (end.0 - start.0, end.1 - start.1);
|
||||
let length = distance(start, end);
|
||||
if length < tuning.min_travel {
|
||||
return near;
|
||||
}
|
||||
let origin = nearest(start, targets, tuning.radius);
|
||||
if near != origin {
|
||||
return near;
|
||||
}
|
||||
// Still nearest where it started: a quick flick toward a neighbour.
|
||||
let Some(o) = origin else {
|
||||
return near;
|
||||
};
|
||||
let from = targets[o];
|
||||
let heading = (travel.0 / length, travel.1 / length);
|
||||
let next = targets
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|(i, _)| *i != o)
|
||||
.filter_map(|(i, t)| {
|
||||
let to = (t.0 - from.0, t.1 - from.1);
|
||||
let gap = distance(from, *t);
|
||||
let aligned = (to.0 * heading.0 + to.1 * heading.1) / gap;
|
||||
(gap > 0.0 && aligned >= tuning.cone).then_some((i, gap, to))
|
||||
})
|
||||
.min_by(|a, b| a.1.total_cmp(&b.1));
|
||||
match next {
|
||||
Some((i, gap, to)) => {
|
||||
let progress = ((end.0 - from.0) * to.0 + (end.1 - from.1) * to.1) / (gap * gap);
|
||||
if progress >= tuning.commit {
|
||||
Some(i)
|
||||
} else {
|
||||
near
|
||||
}
|
||||
}
|
||||
None => near,
|
||||
}
|
||||
}
|
||||
|
||||
/// The cursor `seconds` into a glide from `from` to `to`: eased out, so it
|
||||
/// slows as it lands, and exactly `to` once the glide is over.
|
||||
pub fn glide(from: Point, to: Point, seconds: f32, tuning: &Tuning) -> Point {
|
||||
let t = (seconds / tuning.glide_seconds).clamp(0.0, 1.0);
|
||||
let eased = 1.0 - (1.0 - t).powi(3);
|
||||
(
|
||||
from.0 + (to.0 - from.0) * eased,
|
||||
from.1 + (to.1 - from.1) * eased,
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
/// A row of inventory slots, 18 pixels apart, and the slot below the first.
|
||||
const SLOTS: [Point; 4] = [(8.0, 8.0), (26.0, 8.0), (44.0, 8.0), (8.0, 26.0)];
|
||||
|
||||
#[test]
|
||||
fn a_short_flick_moves_to_the_neighbour_it_heads_for() {
|
||||
// 4 pixels right of slot 0: still nearest slot 0, but heading for slot 1.
|
||||
assert_eq!(settle((8.0, 8.0), (12.0, 8.0), &SLOTS, &TUNING), Some(1));
|
||||
assert_eq!(settle((8.0, 8.0), (8.0, 12.0), &SLOTS, &TUNING), Some(3));
|
||||
assert_eq!(settle((26.0, 8.0), (22.0, 8.0), &SLOTS, &TUNING), Some(0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_wobble_stays_put() {
|
||||
assert_eq!(settle((8.0, 8.0), (8.5, 8.4), &SLOTS, &TUNING), Some(0));
|
||||
// Barely started toward the neighbour: not committed.
|
||||
assert_eq!(settle((8.0, 8.0), (9.6, 8.0), &SLOTS, &TUNING), Some(0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_long_move_settles_on_the_nearest_target() {
|
||||
assert_eq!(settle((8.0, 8.0), (42.0, 9.0), &SLOTS, &TUNING), Some(2));
|
||||
// Far from everything: left where it is.
|
||||
assert_eq!(settle((8.0, 8.0), (200.0, 200.0), &SLOTS, &TUNING), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_flick_off_any_row_does_not_jump_sideways() {
|
||||
// Up from slot 0: nothing lies that way, so it stays on slot 0.
|
||||
assert_eq!(settle((8.0, 8.0), (8.0, 4.0), &SLOTS, &TUNING), Some(0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_glide_eases_onto_its_target_and_stops_there() {
|
||||
let (from, to) = ((0.0, 0.0), (20.0, -10.0));
|
||||
assert_eq!(glide(from, to, 0.0, &TUNING), from);
|
||||
let half = glide(from, to, TUNING.glide_seconds / 2.0, &TUNING);
|
||||
assert!(
|
||||
half.0 > 10.0 && half.0 < 20.0,
|
||||
"eased out: past halfway at half time"
|
||||
);
|
||||
assert_eq!(glide(from, to, TUNING.glide_seconds, &TUNING), to);
|
||||
assert_eq!(glide(from, to, 1.0, &TUNING), to);
|
||||
}
|
||||
}
|
||||
@@ -68,7 +68,7 @@ fn fixture(window: Arc<Window>) -> Result<(), Box<dyn std::error::Error>> {
|
||||
true,
|
||||
))?;
|
||||
assert!(!renderer.pack_entity_shadows(), "no selected pack");
|
||||
renderer.set_shader_pack(0, None, &[]);
|
||||
renderer.set_shader_pack(0, None, &[]).unwrap();
|
||||
assert!(
|
||||
!renderer.pack_entity_shadows(),
|
||||
"selected pack without a compiled post"
|
||||
@@ -165,6 +165,7 @@ fn fixture(window: Arc<Window>) -> Result<(), Box<dyn std::error::Error>> {
|
||||
}
|
||||
let (_, notes) = renderer
|
||||
.set_shader_pack(dimension, Some(post), &[])
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
if break_pipeline {
|
||||
assert!(
|
||||
|
||||
@@ -190,8 +190,9 @@ fn replay(window: Arc<Window>) -> Result<(), Box<dyn std::error::Error>> {
|
||||
}
|
||||
let one = [255u8; 4];
|
||||
let zero = [0u8; 4];
|
||||
let pixels = render.pixels.get();
|
||||
let prepared = PreparedTextures::new(
|
||||
&render.pixels,
|
||||
&pixels,
|
||||
render.sprite_size,
|
||||
render.texture_layers,
|
||||
&render.sprite_mips,
|
||||
@@ -206,7 +207,7 @@ fn replay(window: Arc<Window>) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let mut renderer = pollster::block_on(Renderer::new(
|
||||
window,
|
||||
true,
|
||||
&render.pixels,
|
||||
&pixels,
|
||||
render.sprite_size,
|
||||
render.sprite_minimum_size,
|
||||
render.texture_layers,
|
||||
@@ -224,6 +225,8 @@ fn replay(window: Arc<Window>) -> Result<(), Box<dyn std::error::Error>> {
|
||||
false,
|
||||
false,
|
||||
))?;
|
||||
drop(pixels);
|
||||
render.pixels.pack();
|
||||
let state = &scene.renderer;
|
||||
let [width, height] = o.size.unwrap_or(state.size);
|
||||
renderer.resize(width, height);
|
||||
|
||||
@@ -79,7 +79,10 @@ fn pack(renderer: &mut Renderer, folder: &Path, valid: bool) {
|
||||
let (properties, _) = horizon_shaders::read_properties(&pack, &mut macros);
|
||||
let post = horizon_shaders::load_post(&pack, "", &properties, ¯os, &renderer.pack_inputs());
|
||||
assert_eq!(post.notes.is_empty(), valid, "{:?}", post.notes);
|
||||
let (_, notes) = renderer.set_shader_pack(0, Some(post), &[]).unwrap();
|
||||
let (_, notes) = renderer
|
||||
.set_shader_pack(0, Some(post), &[])
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
assert!(
|
||||
!valid || notes.iter().all(|n| !n.contains("skipped")),
|
||||
"{notes:?}"
|
||||
@@ -378,6 +381,7 @@ fn fixture_frame(hud: &HudBatch) -> Frame<'_> {
|
||||
celestial: &[],
|
||||
stars: None,
|
||||
hand: &[],
|
||||
hand_items: &[],
|
||||
hand_fov_degrees: 70.0,
|
||||
screen: &[],
|
||||
pack: Default::default(),
|
||||
|
||||
@@ -84,7 +84,9 @@ pub struct Assets {
|
||||
pub struct RenderAssets {
|
||||
pub sprite_size: u32,
|
||||
pub sprite_minimum_size: u32,
|
||||
pub pixels: Vec<u8>,
|
||||
/// The block sprites' RGBA, layer by layer: as built until a renderer has
|
||||
/// them, then kept compressed ([`SpritePixels`]).
|
||||
pub pixels: SpritePixels,
|
||||
pub texture_layers: u32,
|
||||
pub model_catalog: crate::models::StateModels,
|
||||
/// Shared parsed resources; item-only validation errors surface at item preparation.
|
||||
@@ -111,6 +113,76 @@ pub struct RenderAssets {
|
||||
/// sprites are when it changes (`native_block_sprites_version`).
|
||||
pub generation: u64,
|
||||
}
|
||||
/// The block sprites' pixels for a renderer to upload. Once a renderer has
|
||||
/// them ([`Self::pack`]) they are kept lz4-compressed: the GPU holds the
|
||||
/// texture array, and the copy only serves a renderer made again (another
|
||||
/// window, a lost device, another graphics API), which waits for
|
||||
/// [`Self::get`] to uncompress them. Shared by the window and the workers'
|
||||
/// `RenderAssets`, so the compressed form replaces the raw one in place.
|
||||
pub struct SpritePixels(Arc<PixelStore>);
|
||||
struct PixelStore {
|
||||
len: usize,
|
||||
/// Set by the first `pack`: later calls cost one atomic read.
|
||||
packing: std::sync::atomic::AtomicBool,
|
||||
/// As built; dropped once `packed` holds them.
|
||||
raw: std::sync::Mutex<Option<Arc<Vec<u8>>>>,
|
||||
packed: std::sync::OnceLock<Vec<u8>>,
|
||||
}
|
||||
impl SpritePixels {
|
||||
pub fn new(pixels: Vec<u8>) -> Self {
|
||||
Self(Arc::new(PixelStore {
|
||||
len: pixels.len(),
|
||||
packing: std::sync::atomic::AtomicBool::new(false),
|
||||
raw: std::sync::Mutex::new(Some(Arc::new(pixels))),
|
||||
packed: std::sync::OnceLock::new(),
|
||||
}))
|
||||
}
|
||||
/// Their size in bytes, uncompressed.
|
||||
pub fn len(&self) -> usize {
|
||||
self.0.len
|
||||
}
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.0.len == 0
|
||||
}
|
||||
/// The pixels as built, uncompressed again once packed.
|
||||
pub fn get(&self) -> Arc<Vec<u8>> {
|
||||
let raw = self.0.raw.lock().unwrap_or_else(|e| e.into_inner()).clone();
|
||||
raw.unwrap_or_else(|| {
|
||||
let packed = self.0.packed.get().map(Vec::as_slice).unwrap_or_default();
|
||||
Arc::new(
|
||||
lz4_flex::decompress_size_prepended(packed)
|
||||
.ok()
|
||||
.filter(|p| p.len() == self.0.len)
|
||||
.unwrap_or_else(|| vec![0; self.0.len]),
|
||||
)
|
||||
})
|
||||
}
|
||||
/// Keep them compressed from now on, once a renderer has uploaded them:
|
||||
/// compressed on a thread of their own, the raw copy dropped after.
|
||||
pub fn pack(&self) {
|
||||
use std::sync::atomic::Ordering;
|
||||
if self.0.len == 0 || self.0.packing.swap(true, Ordering::Relaxed) {
|
||||
return;
|
||||
}
|
||||
let store = self.0.clone();
|
||||
let job = move || {
|
||||
let raw = store.raw.lock().unwrap_or_else(|e| e.into_inner()).clone();
|
||||
if let Some(raw) = raw {
|
||||
let _ = store.packed.set(lz4_flex::compress_prepend_size(&raw));
|
||||
// `get` reads the compressed copy from here on.
|
||||
*store.raw.lock().unwrap_or_else(|e| e.into_inner()) = None;
|
||||
}
|
||||
};
|
||||
let fallback = job.clone();
|
||||
if std::thread::Builder::new()
|
||||
.name("Sprite packing".into())
|
||||
.spawn(job)
|
||||
.is_err()
|
||||
{
|
||||
fallback();
|
||||
}
|
||||
}
|
||||
}
|
||||
/// The last `RenderAssets::generation` handed out.
|
||||
static GENERATION: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
|
||||
fn invalid(message: &str) -> io::Error {
|
||||
@@ -333,7 +405,7 @@ impl RenderAssets {
|
||||
sprite_size: sprites.size,
|
||||
sprite_minimum_size: sprites.minimum_size,
|
||||
texture_layers: u32::try_from(sprites.count())?,
|
||||
pixels: sprites.pixels,
|
||||
pixels: SpritePixels::new(sprites.pixels),
|
||||
model_catalog: models.catalog,
|
||||
model_library,
|
||||
model_placements: models.placements,
|
||||
@@ -431,4 +503,29 @@ mod tests {
|
||||
[ConsumeEffect::ApplyEffects { probability, .. }] if probability == 0.3
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sprite_pixels_come_back_the_same_once_packed() {
|
||||
// Two layers of 16x16 RGBA with some structure, as sprites have.
|
||||
let pixels: Vec<u8> = (0..2 * 16 * 16 * 4).map(|i| (i * 7 % 251) as u8).collect();
|
||||
let stored = super::SpritePixels::new(pixels.clone());
|
||||
assert_eq!(*stored.get(), pixels);
|
||||
stored.pack();
|
||||
stored.pack();
|
||||
// The packing thread drops the raw copy once the compressed one is set.
|
||||
let started = std::time::Instant::now();
|
||||
while stored.0.raw.lock().unwrap().is_some() {
|
||||
assert!(started.elapsed().as_secs() < 10, "packing never finished");
|
||||
std::thread::yield_now();
|
||||
}
|
||||
assert!(
|
||||
stored
|
||||
.0
|
||||
.packed
|
||||
.get()
|
||||
.is_some_and(|p| p.len() < pixels.len())
|
||||
);
|
||||
assert_eq!(*stored.get(), pixels);
|
||||
assert_eq!(stored.len(), pixels.len());
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ use crate::{
|
||||
block_entity_anim::{self, EnchantingBook},
|
||||
breaking::entity_geometry,
|
||||
fast_hash::FxHashMap,
|
||||
font::Glyph,
|
||||
gfx::mark_oit,
|
||||
hud::Rect,
|
||||
mesher::{CULL_BACK, Vertex},
|
||||
@@ -660,7 +661,7 @@ fn sign_text_calls(
|
||||
} else {
|
||||
(dark, 0, vertex_light(packed))
|
||||
};
|
||||
let advance = |c: char| (scene.glyph)(c).1;
|
||||
let advance = |c: char| (scene.glyph)(c).advance;
|
||||
let width = |s: &str| s.chars().map(advance).sum::<f32>().ceil();
|
||||
text.lines
|
||||
.iter()
|
||||
@@ -699,10 +700,19 @@ fn draw_text(scene: &Scene, call: &TextCall, out: &mut Vec<Vertex>) {
|
||||
let mut x = call.x + dx;
|
||||
let y0 = call.y + dy;
|
||||
for ch in call.text.chars() {
|
||||
let (cell, advance) = (scene.glyph)(ch);
|
||||
if let Some(r) = cell {
|
||||
let corners = [(x, y0 + 8.0), (x + 8.0, y0 + 8.0), (x + 8.0, y0), (x, y0)];
|
||||
let uvs = [[r.u0, r.v1], [r.u1, r.v1], [r.u1, r.v0], [r.u0, r.v0]];
|
||||
let g = (scene.glyph)(ch);
|
||||
if let Some(cell) = g.rect {
|
||||
// BakedSheetGlyph: the glyph's own box from the pen, not a
|
||||
// fixed 8x8 cell (a Unifont glyph is 0.5 units per texel).
|
||||
let (x0, x1) = (x + g.left, x + g.right);
|
||||
let (top, bottom) = (y0 + g.top, y0 + g.bottom);
|
||||
let corners = [(x0, bottom), (x1, bottom), (x1, top), (x0, top)];
|
||||
let uvs = [
|
||||
[cell.u0, cell.v1],
|
||||
[cell.u1, cell.v1],
|
||||
[cell.u1, cell.v0],
|
||||
[cell.u0, cell.v0],
|
||||
];
|
||||
let c =
|
||||
0xFF00_0000 | (argb & 255) << 16 | (argb >> 8 & 255) << 8 | (argb >> 16 & 255);
|
||||
for ((cx, cy), uv) in corners.into_iter().zip(uvs) {
|
||||
@@ -721,7 +731,7 @@ fn draw_text(scene: &Scene, call: &TextCall, out: &mut Vec<Vertex>) {
|
||||
});
|
||||
}
|
||||
}
|
||||
x += advance;
|
||||
x += g.advance;
|
||||
}
|
||||
};
|
||||
if call.outline != 0 {
|
||||
@@ -818,8 +828,8 @@ pub struct Scene<'a> {
|
||||
/// profile → skin): a downloaded `skins/<sha1>` slot or the profile's
|
||||
/// `DefaultPlayerSkin` fallback; None keeps `SKIN_BY_TYPE` (`DefaultPlayerSkin.getDefaultTexture`, slim steve).
|
||||
pub skull: &'a dyn Fn([i32; 3]) -> Option<String>,
|
||||
/// Font glyph cell (none for blank glyphs such as the space) and advance.
|
||||
pub glyph: &'a dyn Fn(char) -> (Option<Rect>, f32),
|
||||
/// Font glyph: atlas cell (none for blank glyphs such as the space), box and advance.
|
||||
pub glyph: &'a dyn Fn(char) -> Glyph,
|
||||
/// Changes whenever `glyph` may answer differently (`Font::epoch`): sign
|
||||
/// text laid out under another value is laid out again.
|
||||
pub glyphs: u64,
|
||||
@@ -3342,7 +3352,7 @@ mod tests {
|
||||
sign: &|_| None,
|
||||
banner: &|_| Vec::new(),
|
||||
skull: &|_| None,
|
||||
glyph: &|_| (None, 0.0),
|
||||
glyph: &|_| Glyph::default(),
|
||||
glyphs: 0,
|
||||
};
|
||||
// Compare the cached world path with the original model renderer,
|
||||
@@ -3610,7 +3620,13 @@ mod tests {
|
||||
w: 8,
|
||||
h: 8,
|
||||
};
|
||||
(Some(rect), 6.0)
|
||||
Glyph {
|
||||
rect: Some(rect),
|
||||
right: 8.0,
|
||||
bottom: 8.0,
|
||||
advance: 6.0,
|
||||
..Glyph::default()
|
||||
}
|
||||
};
|
||||
let scene = Scene {
|
||||
camera: DVec3::ZERO,
|
||||
@@ -3660,6 +3676,78 @@ mod tests {
|
||||
assert!(out.iter().all(|v| v.pos[2] == 0.0));
|
||||
}
|
||||
|
||||
/// BakedSheetGlyph draws a glyph over its own box from the pen
|
||||
/// (x + left .. x + right, y + up .. y + down), not a fixed 8x8 cell. With
|
||||
/// Force Unicode Font a Latin letter is an 8x16 Unifont glyph at half
|
||||
/// scale: 4 units wide and 8 tall, advancing 5 (#8699).
|
||||
#[test]
|
||||
fn sign_text_draws_each_glyph_over_its_own_box() {
|
||||
let world = World::new(BlockStateId(0), 1);
|
||||
let sprites = HashMap::new();
|
||||
let glyph = |_: char| Glyph {
|
||||
rect: Some(Rect {
|
||||
u0: 0.0,
|
||||
v0: 0.0,
|
||||
u1: 0.0625,
|
||||
v1: 0.125,
|
||||
w: 8,
|
||||
h: 16,
|
||||
}),
|
||||
left: 0.0,
|
||||
top: 0.0,
|
||||
right: 4.0,
|
||||
bottom: 8.0,
|
||||
advance: 5.0,
|
||||
offset: 0.5,
|
||||
};
|
||||
let scene = Scene {
|
||||
camera: DVec3::ZERO,
|
||||
orientation: Quat::IDENTITY,
|
||||
anim: &|_| BlockAnim::default(),
|
||||
texts: None,
|
||||
partial: 0.0,
|
||||
game_time: 0,
|
||||
max_y: 320,
|
||||
world: &world,
|
||||
sprites: &sprites,
|
||||
emissive: &Default::default(),
|
||||
translucent_sprites: &HashSet::new(),
|
||||
atlas_revision: 1,
|
||||
nether: false,
|
||||
lid: &|_| 0.0,
|
||||
sign: &|_| None,
|
||||
banner: &|_| Vec::new(),
|
||||
skull: &|_| None,
|
||||
glyph: &glyph,
|
||||
glyphs: 0,
|
||||
};
|
||||
let call = TextCall {
|
||||
matrix: Mat4::IDENTITY,
|
||||
x: 10.0,
|
||||
y: 2.0,
|
||||
text: "ab".into(),
|
||||
color: 0xFF00_0000,
|
||||
outline: 0,
|
||||
light: 240 | 240 << 8,
|
||||
};
|
||||
let mut out = Vec::new();
|
||||
draw_text(&scene, &call, &mut out);
|
||||
let boxes: Vec<_> = out
|
||||
.chunks(4)
|
||||
.map(|q| {
|
||||
let xs = q.iter().map(|v| v.pos[0]);
|
||||
let ys = q.iter().map(|v| v.pos[1]);
|
||||
[
|
||||
xs.clone().fold(f32::MAX, f32::min),
|
||||
xs.fold(f32::MIN, f32::max),
|
||||
ys.clone().fold(f32::MAX, f32::min),
|
||||
ys.fold(f32::MIN, f32::max),
|
||||
]
|
||||
})
|
||||
.collect();
|
||||
assert_eq!(boxes, [[10.0, 14.0, 2.0, 10.0], [15.0, 19.0, 2.0, 10.0]]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cached_sign_text_matches_and_follows_changes() {
|
||||
let renderer = BlockEntityRenderer {
|
||||
@@ -3714,7 +3802,13 @@ mod tests {
|
||||
w: 8,
|
||||
h: 8,
|
||||
};
|
||||
((c != ' ').then_some(rect), wide.get())
|
||||
Glyph {
|
||||
rect: (c != ' ').then_some(rect),
|
||||
right: 8.0,
|
||||
bottom: 8.0,
|
||||
advance: wide.get(),
|
||||
..Glyph::default()
|
||||
}
|
||||
};
|
||||
let (first_sign, changed_sign, glowing_sign) = (
|
||||
|_| Some(&first_text),
|
||||
@@ -3879,7 +3973,7 @@ mod tests {
|
||||
sign: &|_| None,
|
||||
banner: &|_| Vec::new(),
|
||||
skull: &|_| None,
|
||||
glyph: &|_| (None, 0.0),
|
||||
glyph: &|_| Glyph::default(),
|
||||
glyphs: 0,
|
||||
};
|
||||
let mut verts = Vec::new();
|
||||
@@ -3964,7 +4058,7 @@ mod tests {
|
||||
sign: &|_| None,
|
||||
banner: &|_| Vec::new(),
|
||||
skull: &|_| None,
|
||||
glyph: &|_| (None, 0.0),
|
||||
glyph: &|_| Glyph::default(),
|
||||
glyphs: 0,
|
||||
};
|
||||
// A closed single chest of `block` drawn by `renderer`: positions and UVs.
|
||||
|
||||
@@ -4,6 +4,7 @@ use crate::{
|
||||
ModelPart, SIGN_TEXT_KEEP, Scene, StaticSectionRevision, classify,
|
||||
},
|
||||
chunk::Chunk,
|
||||
font::Glyph,
|
||||
hud::Rect,
|
||||
mesher::Vertex,
|
||||
signs::{SignData, SignText},
|
||||
@@ -355,7 +356,7 @@ fn batched_callbacks_preserve_entity_ranges_and_allow_immediate_culling() {
|
||||
sign: &|_| None,
|
||||
banner: &|_| Vec::new(),
|
||||
skull: &|_| None,
|
||||
glyph: &|_| (None, 0.0),
|
||||
glyph: &|_| Glyph::default(),
|
||||
glyphs: 0,
|
||||
};
|
||||
// Reverse local-position order to check that cache indexing does not
|
||||
@@ -443,7 +444,7 @@ fn static_cache_qualifies_local_positions_by_section_and_drops_old_entries() {
|
||||
sign: &|_| None,
|
||||
banner: &|_| Vec::new(),
|
||||
skull: &|_| None,
|
||||
glyph: &|_| (None, 0.0),
|
||||
glyph: &|_| Glyph::default(),
|
||||
glyphs: 0,
|
||||
};
|
||||
let options = CacheOptions {
|
||||
@@ -497,7 +498,7 @@ fn gpu_static_cache_uses_section_local_chests_and_keeps_visibility_separate() {
|
||||
sign: &|_| None,
|
||||
banner: &|_| Vec::new(),
|
||||
skull: &|_| None,
|
||||
glyph: &|_| (None, 0.0),
|
||||
glyph: &|_| Glyph::default(),
|
||||
glyphs: 0,
|
||||
};
|
||||
let blocks = [([100, 70, -32], 0)];
|
||||
@@ -651,18 +652,19 @@ fn sign_text_cache_can_be_disabled_and_reenabled_without_changing_output() {
|
||||
};
|
||||
let sign_data = &data;
|
||||
let sign = move |_: [i32; 3]| Some(sign_data);
|
||||
let glyph = |_: char| {
|
||||
(
|
||||
Some(Rect {
|
||||
u0: 0.0,
|
||||
v0: 0.0,
|
||||
u1: 0.0625,
|
||||
v1: 0.0625,
|
||||
w: 8,
|
||||
h: 8,
|
||||
}),
|
||||
6.0,
|
||||
)
|
||||
let glyph = |_: char| Glyph {
|
||||
rect: Some(Rect {
|
||||
u0: 0.0,
|
||||
v0: 0.0,
|
||||
u1: 0.0625,
|
||||
v1: 0.0625,
|
||||
w: 8,
|
||||
h: 8,
|
||||
}),
|
||||
right: 8.0,
|
||||
bottom: 8.0,
|
||||
advance: 6.0,
|
||||
..Glyph::default()
|
||||
};
|
||||
let scene = Scene {
|
||||
camera: DVec3::new(2.25, 64.5, -3.75),
|
||||
@@ -735,7 +737,7 @@ fn shulker_cache_tracks_settled_poses_and_does_not_freeze_opening_animation() {
|
||||
sign: &|_| None,
|
||||
banner: &|_| Vec::new(),
|
||||
skull: &|_| None,
|
||||
glyph: &|_| (None, 0.0),
|
||||
glyph: &|_| Glyph::default(),
|
||||
glyphs: 0,
|
||||
};
|
||||
let blocks = [([0, 64, 0], 0)];
|
||||
@@ -836,7 +838,7 @@ fn shulker_cache_covers_all_colors_and_facing_directions() {
|
||||
sign: &|_| None,
|
||||
banner: &|_| Vec::new(),
|
||||
skull: &|_| None,
|
||||
glyph: &|_| (None, 0.0),
|
||||
glyph: &|_| Glyph::default(),
|
||||
glyphs: 0,
|
||||
};
|
||||
let options = CacheOptions {
|
||||
@@ -890,7 +892,7 @@ fn cached_bells_keep_shaking_until_the_animation_ends() {
|
||||
sign: &|_| None,
|
||||
banner: &|_| Vec::new(),
|
||||
skull: &|_| None,
|
||||
glyph: &|_| (None, 0.0),
|
||||
glyph: &|_| Glyph::default(),
|
||||
glyphs: 0,
|
||||
};
|
||||
let blocks = [([0, 64, 0], 0)];
|
||||
@@ -951,7 +953,7 @@ fn cached_closed_chests_match_the_direct_model_and_rebuild_when_opening() {
|
||||
sign: &|_| None,
|
||||
banner: &|_| Vec::new(),
|
||||
skull: &|_| None,
|
||||
glyph: &|_| (None, 0.0),
|
||||
glyph: &|_| Glyph::default(),
|
||||
glyphs: 0,
|
||||
};
|
||||
let blocks = [([0, 64, 0], 0)];
|
||||
@@ -1046,7 +1048,7 @@ fn closed_chest_cache_covers_all_materials_and_atlas_reloads() {
|
||||
sign: &|_| None,
|
||||
banner: &|_| Vec::new(),
|
||||
skull: &|_| None,
|
||||
glyph: &|_| (None, 0.0),
|
||||
glyph: &|_| Glyph::default(),
|
||||
glyphs: 0,
|
||||
};
|
||||
let pos = [0, 64, 0];
|
||||
@@ -1134,7 +1136,7 @@ fn double_chest_cache_bypasses_both_halves_while_either_lid_is_open() {
|
||||
sign: &|_| None,
|
||||
banner: &|_| Vec::new(),
|
||||
skull: &|_| None,
|
||||
glyph: &|_| (None, 0.0),
|
||||
glyph: &|_| Glyph::default(),
|
||||
glyphs: 0,
|
||||
};
|
||||
let pair = [([0, 64, 0], 0), ([1, 64, 0], 1)];
|
||||
@@ -1209,7 +1211,7 @@ fn decorated_pot_cache_tracks_sherds_and_bypasses_wobble_animation() {
|
||||
sign: &|_| None,
|
||||
banner: &|_| Vec::new(),
|
||||
skull: &|_| None,
|
||||
glyph: &|_| (None, 0.0),
|
||||
glyph: &|_| Glyph::default(),
|
||||
glyphs: 0,
|
||||
};
|
||||
let blocks = [([0, 64, 0], 0)];
|
||||
@@ -1287,7 +1289,7 @@ fn banner_cache_keeps_the_pole_static_while_the_flag_and_patterns_update() {
|
||||
sign: &|_| None,
|
||||
banner: &banner_patterns,
|
||||
skull: &|_| None,
|
||||
glyph: &|_| (None, 0.0),
|
||||
glyph: &|_| Glyph::default(),
|
||||
glyphs: 0,
|
||||
};
|
||||
let blocks = [([0, 64, 0], 0)];
|
||||
@@ -1353,7 +1355,7 @@ fn cached_wall_banner_poles_use_the_wall_model() {
|
||||
sign: &|_| None,
|
||||
banner: &|_| Vec::new(),
|
||||
skull: &|_| None,
|
||||
glyph: &|_| (None, 0.0),
|
||||
glyph: &|_| Glyph::default(),
|
||||
glyphs: 0,
|
||||
};
|
||||
let pos = [0, 64, 0];
|
||||
@@ -1400,7 +1402,7 @@ fn copper_statue_cache_rebuilds_when_its_pose_state_changes() {
|
||||
sign: &|_| None,
|
||||
banner: &|_| Vec::new(),
|
||||
skull: &|_| None,
|
||||
glyph: &|_| (None, 0.0),
|
||||
glyph: &|_| Glyph::default(),
|
||||
glyphs: 0,
|
||||
};
|
||||
let options = CacheOptions {
|
||||
@@ -1505,7 +1507,7 @@ fn copper_statue_cache_covers_weathering_waxing_and_all_poses() {
|
||||
sign: &|_| None,
|
||||
banner: &|_| Vec::new(),
|
||||
skull: &|_| None,
|
||||
glyph: &|_| (None, 0.0),
|
||||
glyph: &|_| Glyph::default(),
|
||||
glyphs: 0,
|
||||
};
|
||||
let options = CacheOptions {
|
||||
|
||||
@@ -58,6 +58,24 @@ impl DataPack {
|
||||
}
|
||||
out
|
||||
}
|
||||
/// The files of `data/<namespace>/<folder>/` in every namespace, as
|
||||
/// `list` names them; a folder pack walks only those folders.
|
||||
pub fn list_folder(&self, folder: &str) -> Vec<String> {
|
||||
let files = self.list_kinds(&[folder]);
|
||||
let Source::Zip(_) = &self.source else {
|
||||
return files;
|
||||
};
|
||||
files
|
||||
.into_iter()
|
||||
.filter(|f| {
|
||||
f.strip_prefix("data/")
|
||||
.and_then(|r| r.split_once('/'))
|
||||
.is_some_and(|(_, r)| {
|
||||
r.strip_prefix(folder).is_some_and(|r| r.starts_with('/'))
|
||||
})
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
pub fn read(&self, path: &str) -> Option<Vec<u8>> {
|
||||
match &self.source {
|
||||
Source::Zip(z) => z.read(path).ok(),
|
||||
|
||||
@@ -8,6 +8,8 @@ use std::{collections::VecDeque, fs, path::Path};
|
||||
pub const FILE: &str = "horizon-extras.txt";
|
||||
/// The name the options screen uses while the sort key waits for a key.
|
||||
pub const SORT_KEY: &str = "horizon.sort";
|
||||
/// The 3D skin layers line, here and in the `options.txt` that held it first.
|
||||
const SKIN_LAYERS_KEY: &str = "threeDSkinLayers";
|
||||
|
||||
/// The minimap's sizes in GUI pixels, and its zooms in blocks per pixel.
|
||||
pub const MINIMAP_SIZES: [(u8, &str); 3] = [(64, "Small"), (96, "Medium"), (128, "Large")];
|
||||
@@ -76,6 +78,13 @@ pub struct Extras {
|
||||
pub zoom_smooth: bool,
|
||||
/// Divide mouse turning by the zoom.
|
||||
pub zoom_sensitivity: bool,
|
||||
/// Far terrain a zoom magnifies is planned finer, so a spyglass does not
|
||||
/// show the coarse cells it was given for an unzoomed screen
|
||||
/// (`lod::Aim`). Costs far tiles while the zoom is held and gives them
|
||||
/// back after, and does nothing at all unless far terrain is on
|
||||
/// (`lodDistance`) and the view is actually zoomed. Off by default until
|
||||
/// a measurement shows the extra tiles land while the zoom is still held.
|
||||
pub lod_zoom_detail: bool,
|
||||
/// The FPS counter and keystrokes extras are official mods now: their
|
||||
/// old settings stay here, kept as they were.
|
||||
pub fps: bool,
|
||||
@@ -157,6 +166,10 @@ pub struct Extras {
|
||||
pub cosmetics_mine: bool,
|
||||
pub cosmetics_others: horizon_cosmetics::prefs::Others,
|
||||
pub cosmetics_auras: bool,
|
||||
/// 3D skin layers (`threeDSkinLayers`, Options → Skin Customization): each
|
||||
/// painted texel of a player's outer layer drawn as a slab
|
||||
/// (`horizon_client::mobs::skin_layers`).
|
||||
pub three_d_skin_layers: bool,
|
||||
}
|
||||
impl Default for Extras {
|
||||
fn default() -> Self {
|
||||
@@ -169,6 +182,7 @@ impl Default for Extras {
|
||||
zoom_level: 4,
|
||||
zoom_smooth: true,
|
||||
zoom_sensitivity: true,
|
||||
lod_zoom_detail: false,
|
||||
fps: false,
|
||||
fps_corner: Corner::TopLeft,
|
||||
fps_lows: false,
|
||||
@@ -206,6 +220,7 @@ impl Default for Extras {
|
||||
cosmetics_mine: true,
|
||||
cosmetics_others: horizon_cosmetics::prefs::Others::Shown,
|
||||
cosmetics_auras: false,
|
||||
three_d_skin_layers: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -243,6 +258,7 @@ impl Extras {
|
||||
}
|
||||
"zoomSmooth" => e.zoom_smooth = flag(e.zoom_smooth),
|
||||
"zoomSensitivity" => e.zoom_sensitivity = flag(e.zoom_sensitivity),
|
||||
"lodZoomDetail" => e.lod_zoom_detail = flag(e.lod_zoom_detail),
|
||||
"fps" => e.fps = flag(e.fps),
|
||||
"fpsCorner" => e.fps_corner = Corner::parse(value, e.fps_corner),
|
||||
"fpsLows" => e.fps_lows = flag(e.fps_lows),
|
||||
@@ -307,6 +323,7 @@ impl Extras {
|
||||
horizon_cosmetics::prefs::Others::parse(value).unwrap_or(e.cosmetics_others)
|
||||
}
|
||||
"cosmeticsAuras" => e.cosmetics_auras = flag(e.cosmetics_auras),
|
||||
SKIN_LAYERS_KEY => e.three_d_skin_layers = flag(e.three_d_skin_layers),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
@@ -314,7 +331,7 @@ impl Extras {
|
||||
}
|
||||
pub fn serialize(&self) -> String {
|
||||
format!(
|
||||
"packBrowser:{}\nfullbright:{}\ndynamicLights:{}\nzoom:{}\nzoomKey:{}\nzoomLevel:{}\nzoomSmooth:{}\nzoomSensitivity:{}\nfps:{}\nfpsCorner:{}\nfpsLows:{}\nkeystrokes:{}\nkeystrokesCorner:{}\nkeystrokesCps:{}\nmovedToMods:{}\nminimap:{}\nminimapCorner:{}\nminimapSize:{}\nminimapShape:{}\nminimapZoom:{}\nminimapRotate:{}\nautoReconnect:{}\nuiSoundReserve:{}\nownNameTag:{}\nhideBlockParticles:{}\nmouseTweaks:{}\nmouseTweaksWheel:{}\nsort:{}\nsortKey:{}\nchatAnimation:{}\nchatIndicator:{}\n{}:{}\nagentControl:{}\nreproKeys:{}\ndiscordPresence:{}\nsplitscreen:{}\nsplitscreenTwo:{}\nsplitscreenThree:{}\nsplitscreenNames:{}\nwheelCyclesSettings:{}\nmusicOff:{}\nmusicPage:{}\ncosmeticsMine:{}\ncosmeticsOthers:{}\ncosmeticsAuras:{}\n",
|
||||
"packBrowser:{}\nfullbright:{}\ndynamicLights:{}\nzoom:{}\nzoomKey:{}\nzoomLevel:{}\nzoomSmooth:{}\nzoomSensitivity:{}\nlodZoomDetail:{}\nfps:{}\nfpsCorner:{}\nfpsLows:{}\nkeystrokes:{}\nkeystrokesCorner:{}\nkeystrokesCps:{}\nmovedToMods:{}\nminimap:{}\nminimapCorner:{}\nminimapSize:{}\nminimapShape:{}\nminimapZoom:{}\nminimapRotate:{}\nautoReconnect:{}\nuiSoundReserve:{}\nownNameTag:{}\nhideBlockParticles:{}\nmouseTweaks:{}\nmouseTweaksWheel:{}\nsort:{}\nsortKey:{}\nchatAnimation:{}\nchatIndicator:{}\n{}:{}\nagentControl:{}\nreproKeys:{}\ndiscordPresence:{}\nsplitscreen:{}\nsplitscreenTwo:{}\nsplitscreenThree:{}\nsplitscreenNames:{}\nwheelCyclesSettings:{}\nmusicOff:{}\nmusicPage:{}\ncosmeticsMine:{}\ncosmeticsOthers:{}\ncosmeticsAuras:{}\n{}:{}\n",
|
||||
bool_text(self.pack_browser),
|
||||
bool_text(self.fullbright),
|
||||
bool_text(self.dynamic_lights),
|
||||
@@ -323,6 +340,7 @@ impl Extras {
|
||||
self.zoom_level,
|
||||
bool_text(self.zoom_smooth),
|
||||
bool_text(self.zoom_sensitivity),
|
||||
bool_text(self.lod_zoom_detail),
|
||||
bool_text(self.fps),
|
||||
self.fps_corner.name(),
|
||||
bool_text(self.fps_lows),
|
||||
@@ -365,8 +383,28 @@ impl Extras {
|
||||
bool_text(self.cosmetics_mine),
|
||||
self.cosmetics_others.name(),
|
||||
bool_text(self.cosmetics_auras),
|
||||
SKIN_LAYERS_KEY,
|
||||
bool_text(self.three_d_skin_layers),
|
||||
)
|
||||
}
|
||||
/// Adopts the settings `options.txt` held before they moved here, while
|
||||
/// this file (`own`) has no line of its own: 3D skin layers was an
|
||||
/// `options.txt` line. Vanilla's `Options.save` drops lines it doesn't
|
||||
/// know, so it is read there once, the first start after the update.
|
||||
pub fn read_old_options(&mut self, own: &str, options_txt: &str) {
|
||||
fn line(text: &str) -> Option<&str> {
|
||||
text.lines().find_map(|l| {
|
||||
l.split_once(':')
|
||||
.filter(|(key, _)| *key == SKIN_LAYERS_KEY)
|
||||
.map(|(_, value)| value)
|
||||
})
|
||||
}
|
||||
if line(own).is_none()
|
||||
&& let Some(value) = line(options_txt)
|
||||
{
|
||||
self.three_d_skin_layers = value == "true";
|
||||
}
|
||||
}
|
||||
/// Binds the extra key `name` (`SORT_KEY`); false for
|
||||
/// another name (a vanilla mapping).
|
||||
pub fn set_key(&mut self, name: &str, value: String) -> bool {
|
||||
|
||||
@@ -24,7 +24,7 @@ pub const DEFAULT: &str = "minecraft:default";
|
||||
|
||||
/// A glyph ready to draw: atlas UVs and its box relative to the pen
|
||||
/// position (GlyphBitmap left/top/right/bottom), in GUI pixels.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
pub struct Glyph {
|
||||
pub rect: Option<Rect>,
|
||||
pub left: f32,
|
||||
@@ -134,6 +134,7 @@ pub struct Font {
|
||||
/// Atlas size and the reserved dynamic region (y, height).
|
||||
atlas: (u32, u32),
|
||||
region: (u32, u32),
|
||||
metrics_only: bool,
|
||||
cache: RefCell<Cache>,
|
||||
/// Set anew for each font and each `reset_cache` (see `epoch`).
|
||||
generation: std::cell::Cell<u64>,
|
||||
@@ -284,6 +285,7 @@ fn load_bitmap(
|
||||
sheets: &HashMap<String, Rect>,
|
||||
pixels: &[u8],
|
||||
atlas: (u32, u32),
|
||||
metrics_only: bool,
|
||||
) -> HashMap<char, BitmapGlyph> {
|
||||
let mut out = HashMap::new();
|
||||
let file = p["file"].as_str().unwrap_or("");
|
||||
@@ -349,6 +351,10 @@ fn load_bitmap(
|
||||
advance: (0.5 + used as f32 * scale).floor() + 1.0,
|
||||
offset: 1.0,
|
||||
};
|
||||
if metrics_only {
|
||||
out.insert(*ch, BitmapGlyph::Atlas(glyph));
|
||||
continue;
|
||||
}
|
||||
let glyph = match &sheet {
|
||||
None => BitmapGlyph::Atlas(Glyph {
|
||||
rect: Some(glyph_rect(
|
||||
@@ -596,6 +602,30 @@ impl Font {
|
||||
atlas: (u32, u32),
|
||||
region: (u32, u32),
|
||||
white: Rect,
|
||||
) -> Self {
|
||||
Self::load_with(root, sprites, pixels, atlas, region, white, false)
|
||||
}
|
||||
/// A server measures text but never draws it. Decode bitmap sheets only
|
||||
/// to obtain advances, then release their pixels; never rasterize glyphs.
|
||||
pub fn metrics(root: &Path) -> Self {
|
||||
let white = Rect {
|
||||
u0: 0.0,
|
||||
v0: 0.0,
|
||||
u1: 1.0,
|
||||
v1: 1.0,
|
||||
w: 1,
|
||||
h: 1,
|
||||
};
|
||||
Self::load_with(root, &HashMap::new(), &[], (1, 1), (0, 0), white, true)
|
||||
}
|
||||
fn load_with(
|
||||
root: &Path,
|
||||
sprites: &HashMap<String, Rect>,
|
||||
pixels: &[u8],
|
||||
atlas: (u32, u32),
|
||||
region: (u32, u32),
|
||||
white: Rect,
|
||||
metrics_only: bool,
|
||||
) -> Self {
|
||||
let sheets = sprites
|
||||
.iter()
|
||||
@@ -617,6 +647,7 @@ impl Font {
|
||||
root: root.to_owned(),
|
||||
atlas,
|
||||
region,
|
||||
metrics_only,
|
||||
cache: RefCell::new(Cache {
|
||||
sets: Vec::new(),
|
||||
region: Region {
|
||||
@@ -665,7 +696,14 @@ impl Font {
|
||||
)),
|
||||
"bitmap" => Some(Provider::Bitmap(
|
||||
Filter::of(p),
|
||||
load_bitmap(&self.root, p, &self.sheets, pixels, self.atlas),
|
||||
load_bitmap(
|
||||
&self.root,
|
||||
p,
|
||||
&self.sheets,
|
||||
pixels,
|
||||
self.atlas,
|
||||
self.metrics_only,
|
||||
),
|
||||
)),
|
||||
"unihex" => Some(Provider::Unihex(Filter::of(p), p.clone(), None)),
|
||||
"ttf" => Some(Provider::TrueType(
|
||||
@@ -841,6 +879,14 @@ impl Font {
|
||||
if let Some(id) = ttf.ids.get(&c)
|
||||
&& !(non_fishy && fishy_advance(ttf.advance(*id)))
|
||||
{
|
||||
if self.metrics_only {
|
||||
return Some(Glyph {
|
||||
rect: None,
|
||||
advance: ttf.advance(*id),
|
||||
offset: 1.0,
|
||||
..self.missing
|
||||
});
|
||||
}
|
||||
let (glyph, bitmap) = ttf.glyph(*id);
|
||||
return match bitmap {
|
||||
Some((w, h, rgba)) => {
|
||||
@@ -861,6 +907,17 @@ impl Font {
|
||||
}
|
||||
fn rasterize_hex(&self, region: &mut Region, h: HexGlyph) -> Option<Glyph> {
|
||||
let width = h.right.saturating_sub(h.left) + 1;
|
||||
if self.metrics_only {
|
||||
return Some(Glyph {
|
||||
rect: None,
|
||||
left: 0.0,
|
||||
top: 0.0,
|
||||
right: width as f32 / 2.0,
|
||||
bottom: 8.0,
|
||||
advance: hex_advance(&h),
|
||||
offset: 0.5,
|
||||
});
|
||||
}
|
||||
let mut rgba = Vec::with_capacity((width * 16 * 4) as usize);
|
||||
for row in h.rows {
|
||||
for bit in h.left..=h.right {
|
||||
@@ -1361,6 +1418,55 @@ mod tests {
|
||||
out
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn server_metrics_preserve_bitmap_true_type_and_unihex_advances() {
|
||||
let sheet = png(16, 8, |x, _| x < 2 || (8..14).contains(&x));
|
||||
let def = br#"{"providers":[{"type":"space","advances":{" ":4}},{"type":"bitmap","file":"minecraft:font/a.png","ascent":7,"chars":["ab"]}]}"#;
|
||||
let ttf = br#"{"providers":[{"type":"ttf","file":"minecraft:mono.ttf","size":11,"oversample":2}]}"#;
|
||||
let root = root(
|
||||
"metrics",
|
||||
&[
|
||||
("assets/minecraft/font/default.json", def),
|
||||
("assets/minecraft/font/alt.json", ttf),
|
||||
(
|
||||
"assets/minecraft/font/mono.ttf",
|
||||
horizon_theme::fonts::GEIST_MONO,
|
||||
),
|
||||
("assets/minecraft/textures/font/a.png", &sheet),
|
||||
],
|
||||
);
|
||||
let rendered = load(&root);
|
||||
let metrics = Font::metrics(&root);
|
||||
assert_eq!(metrics.width("a b"), 14.0);
|
||||
assert_eq!(metrics.width("§lab"), 12.0);
|
||||
let text = Text::literal("ab ab");
|
||||
assert_eq!(
|
||||
metrics.split_formatted(&text, 10.0),
|
||||
rendered.split_formatted(&text, 10.0)
|
||||
);
|
||||
let alt = Style {
|
||||
font: Some("minecraft:alt".into()),
|
||||
bold: Some(true),
|
||||
..Style::default()
|
||||
};
|
||||
for c in ['A', 'i', ' ', '\u{fffd}'] {
|
||||
assert_eq!(metrics.advance(c, &alt), rendered.advance(c, &alt));
|
||||
assert!(metrics.glyph_styled(c, &alt).rect.is_none());
|
||||
}
|
||||
let mut hex = HashMap::new();
|
||||
parse_hex(b"0041:0000000018242442427E424242420000\n", &mut hex);
|
||||
let h = hex[&0x41];
|
||||
let glyph = metrics
|
||||
.rasterize_hex(&mut metrics.cache.borrow_mut().region, h)
|
||||
.unwrap();
|
||||
assert_eq!(glyph.advance, 4.0);
|
||||
assert_eq!(glyph.offset, 0.5);
|
||||
assert!(glyph.rect.is_none());
|
||||
assert!(metrics.take_patches().is_empty());
|
||||
assert!(!rendered.take_patches().is_empty());
|
||||
let _ = std::fs::remove_dir_all(root);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn true_type_glyphs_are_rasterized_at_the_provider_size() {
|
||||
let def = br#"{"providers":[{"type":"ttf","file":"minecraft:mono.ttf","size":11,"oversample":2,"shift":[0.5,1],"skip":["B"]}]}"#;
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -885,6 +885,7 @@ mod tests {
|
||||
sorted_indices: None,
|
||||
flat_id: None,
|
||||
gpu_id: None,
|
||||
gpu_fading: false,
|
||||
fading: None,
|
||||
leaving: None,
|
||||
animated_layers: Box::new([]),
|
||||
@@ -1081,6 +1082,7 @@ mod tests {
|
||||
sorted_indices: None,
|
||||
flat_id: Some(id),
|
||||
gpu_id: None,
|
||||
gpu_fading: false,
|
||||
fading: None,
|
||||
leaving: None,
|
||||
animated_layers: Box::new([]),
|
||||
@@ -1307,6 +1309,7 @@ mod tests {
|
||||
sorted_indices: (translucent > 0).then_some(if indices { at } else { (7, 7) }),
|
||||
flat_id: None,
|
||||
gpu_id: None,
|
||||
gpu_fading: false,
|
||||
fading: None,
|
||||
leaving: None,
|
||||
animated_layers: Box::new([]),
|
||||
|
||||
@@ -485,6 +485,7 @@ impl Scene {
|
||||
let f = &self.frame;
|
||||
Frame {
|
||||
weather: &[],
|
||||
hand_items: &[],
|
||||
weather_time: crate::weather::Time::new(0, 0.0),
|
||||
camera: DVec3::from_array(f.camera),
|
||||
yaw: f.yaw,
|
||||
|
||||
@@ -14,9 +14,11 @@
|
||||
//! each in one draw (the pipelines cull the faces turned away), with the origin
|
||||
//! the walk would give it: `resident::origin`'s f32 bits, copied, never
|
||||
//! computed on the GPU. Within the render distance the CPU's walk then lists
|
||||
//! only the sections whose translucent quads it draws, or that have no record
|
||||
//! (`Resident::walk`); past it, it lists every section as before.
|
||||
//! Unlike the walk, the pass draws sections fading in or out whole.
|
||||
//! only the sections whose translucent quads it draws, that have no record, or
|
||||
//! that fade (`Resident::walk`); past it, it lists every section as before. A
|
||||
//! section whose instance carries a fade, fading in or out, has its record
|
||||
//! flagged (`FADING`, gfx.rs `mark_fades`) until it is whole: the pass leaves
|
||||
//! it out, and the CPU draws it with its fade.
|
||||
//!
|
||||
//! The graph is the one the walk reads that frame (`occlusion::Reach`). Its
|
||||
//! search keeps the cells it reached as bits too, and `Occlusion` a generation
|
||||
@@ -59,6 +61,7 @@ use super::{
|
||||
upload::Uploads,
|
||||
};
|
||||
use glam::{DVec3, DVec4, Vec3};
|
||||
use std::{cmp::Reverse, collections::BinaryHeap, time::Instant};
|
||||
|
||||
/// One section (`gpu_culling.wgsl`'s `Section`).
|
||||
#[repr(C)]
|
||||
@@ -68,10 +71,14 @@ pub(super) struct Record {
|
||||
key: [i32; 4],
|
||||
/// The first vertex of its solid quads (a draw's base vertex, an i32: a
|
||||
/// page holds fewer vertices), its solid quads, its box (`rounded_box`),
|
||||
/// then a word kept at 0.
|
||||
/// then its flags (`FADING`).
|
||||
a: [u32; 4],
|
||||
}
|
||||
|
||||
/// In `Record::a[3]`: the CPU draws the section's solid quads while it fades
|
||||
/// (gfx.rs `SectionGpu::gpu_fading`), and the pass leaves it out.
|
||||
const FADING: u32 = 1;
|
||||
|
||||
impl Record {
|
||||
const FREE: Self = Self {
|
||||
key: [0, 0, 0, -1],
|
||||
@@ -86,9 +93,19 @@ impl Record {
|
||||
a: [start as u32, quads, boxed, 0],
|
||||
}
|
||||
}
|
||||
/// The record, `FADING` when `on`.
|
||||
pub fn fading(mut self, on: bool) -> Self {
|
||||
if on {
|
||||
self.a[3] |= FADING;
|
||||
}
|
||||
self
|
||||
}
|
||||
fn page(&self) -> Option<u32> {
|
||||
u32::try_from(self.key[3]).ok()
|
||||
}
|
||||
fn is_fading(&self) -> bool {
|
||||
(self.a[3] & FADING) != 0
|
||||
}
|
||||
}
|
||||
|
||||
/// `rounded_box` for bounds past what a box's codes hold, or not finite: no
|
||||
@@ -359,6 +376,10 @@ pub(super) fn supported(
|
||||
// The pass binds 8, the last cave culling's graph.
|
||||
&& limits.max_storage_buffers_per_shader_stage >= 8
|
||||
&& !super::flat::is_broken_intel_vulkan(info)
|
||||
// DX12's count draws leave each draw's base vertex out of `vertex_index`, by which the
|
||||
// pulled solid pipelines (those of a device with flat page groups) read the page.
|
||||
// shortcut: not offered there, until GPU culling's draws carry their base vertex otherwise.
|
||||
&& !(info.backend == wgpu::Backend::Dx12 && flat_min_sections.is_some())
|
||||
}
|
||||
|
||||
/// A buffer that is recreated larger when it must hold more.
|
||||
@@ -419,6 +440,8 @@ pub(super) struct Records {
|
||||
all_dirty: bool,
|
||||
/// Per arena page, the records on it.
|
||||
page_sections: Vec<u32>,
|
||||
/// The records flagged `FADING`.
|
||||
fading: u32,
|
||||
}
|
||||
|
||||
impl Records {
|
||||
@@ -435,6 +458,7 @@ impl Records {
|
||||
};
|
||||
self.records[id as usize] = record;
|
||||
self.add_to(record.key[3] as u32);
|
||||
self.fading += u32::from(record.is_fading());
|
||||
self.mark(id);
|
||||
id
|
||||
}
|
||||
@@ -455,6 +479,7 @@ impl Records {
|
||||
continue;
|
||||
};
|
||||
self.page_sections[page as usize] -= 1;
|
||||
self.fading -= u32::from(self.records[id as usize].is_fading());
|
||||
self.records[id as usize] = Record::FREE;
|
||||
// shortcut: a teleport frees more than `DIRTY_LIMIT`, so `prepare` writes the
|
||||
// whole table (0.6-2.6 ms at render distance 64); upgrade to a list of freed ids
|
||||
@@ -502,6 +527,22 @@ impl Records {
|
||||
self.add_to(page);
|
||||
self.mark(id);
|
||||
}
|
||||
/// The section with `id` began to draw faded, or stopped (gfx.rs
|
||||
/// `SectionGpu::gpu_fading`): its record is `FADING` when `on`.
|
||||
pub fn set_fading(&mut self, id: u32, on: bool) {
|
||||
let page = self.records.get(id as usize).and_then(Record::page);
|
||||
debug_assert!(page.is_some(), "no record {id} to flag");
|
||||
if page.is_none() || self.records[id as usize].is_fading() == on {
|
||||
return;
|
||||
}
|
||||
self.records[id as usize].a[3] ^= FADING;
|
||||
if on {
|
||||
self.fading += 1;
|
||||
} else {
|
||||
self.fading -= 1;
|
||||
}
|
||||
self.mark(id);
|
||||
}
|
||||
/// Every section went.
|
||||
pub fn clear(&mut self) {
|
||||
self.records.clear();
|
||||
@@ -510,12 +551,17 @@ impl Records {
|
||||
self.dirty = Vec::new();
|
||||
self.all_dirty = false;
|
||||
self.page_sections.clear();
|
||||
self.fading = 0;
|
||||
}
|
||||
/// The sections with a record.
|
||||
pub fn live(&self) -> usize {
|
||||
let free: u32 = self.free.iter().map(|word| word.count_ones()).sum();
|
||||
self.records.len() - free as usize
|
||||
}
|
||||
/// The sections whose record is `FADING`, which the CPU draws.
|
||||
pub fn fading(&self) -> u32 {
|
||||
self.fading
|
||||
}
|
||||
/// The record of the section with `id`; `None` for a free id.
|
||||
#[cfg(any(test, debug_assertions))]
|
||||
pub fn at(&self, id: u32) -> Option<&Record> {
|
||||
@@ -549,6 +595,42 @@ impl Records {
|
||||
}
|
||||
}
|
||||
|
||||
/// The flagged sections by when their fade is over at the latest (gfx.rs
|
||||
/// `SectionGpu::fade_end`), for gfx.rs `mark_fades` to look at them again
|
||||
/// then, and the chunk fade-in time their flags were decided with: `None`
|
||||
/// until a frame has decided them, just after GPU culling was switched on.
|
||||
/// The ends of sections that went or were handed back are skipped as they come.
|
||||
#[derive(Default)]
|
||||
pub(super) struct Fades {
|
||||
due: BinaryHeap<Reverse<(Instant, SectionKey)>>,
|
||||
pub fade_ms: Option<u64>,
|
||||
}
|
||||
|
||||
impl Fades {
|
||||
/// The section at `key` is looked at again at `end`.
|
||||
pub fn push(&mut self, end: Instant, key: SectionKey) {
|
||||
self.due.push(Reverse((end, key)));
|
||||
}
|
||||
/// The section of the earliest end at or before `now`, taken out.
|
||||
pub fn pop_due(&mut self, now: Instant) -> Option<SectionKey> {
|
||||
let &Reverse((end, key)) = self.due.peek()?;
|
||||
if end > now {
|
||||
return None;
|
||||
}
|
||||
self.due.pop();
|
||||
Some(key)
|
||||
}
|
||||
/// Every end goes; `fade_ms` stays.
|
||||
pub fn clear(&mut self) {
|
||||
self.due.clear();
|
||||
}
|
||||
/// The sections an end is waited for.
|
||||
#[cfg(debug_assertions)]
|
||||
pub fn pending(&self) -> impl Iterator<Item = SectionKey> {
|
||||
self.due.iter().map(|r| r.0.1)
|
||||
}
|
||||
}
|
||||
|
||||
/// The pass, its buffers and the records it draws from: made when GPU culling
|
||||
/// is switched on, dropped when it is switched off.
|
||||
pub(super) struct GpuCulling {
|
||||
@@ -574,6 +656,9 @@ pub(super) struct GpuCulling {
|
||||
/// that the arena's compaction moves records while it borrows the
|
||||
/// renderer's other fields.
|
||||
pub records: Records,
|
||||
/// When the flagged records' fades end, a field of its own as `records`
|
||||
/// is: gfx.rs `mark_fades` takes both beside the renderer's sections.
|
||||
pub fades: Fades,
|
||||
/// This frame's pages with records: (page, first draw of its region, the
|
||||
/// region's size).
|
||||
pages: Vec<(u32, u32, u32)>,
|
||||
@@ -700,6 +785,7 @@ impl GpuCulling {
|
||||
reach_generation: None,
|
||||
group: None,
|
||||
records: Records::default(),
|
||||
fades: Fades::default(),
|
||||
pages: Vec::new(),
|
||||
ids: 0,
|
||||
n_updates: 0,
|
||||
@@ -975,8 +1061,8 @@ mod tests {
|
||||
}
|
||||
|
||||
/// Where a section's solid quads are: key, arena page, first vertex, quads,
|
||||
/// and its box.
|
||||
type Placed = (SectionKey, u32, u64, u32, u32);
|
||||
/// its box, and whether it fades (`FADING`).
|
||||
type Placed = (SectionKey, u32, u64, u32, u32, bool);
|
||||
|
||||
/// `gpu_culling.wgsl`'s `near`, on the CPU.
|
||||
fn near(params: &Params, x: i32, z: i32) -> bool {
|
||||
@@ -1025,7 +1111,7 @@ mod tests {
|
||||
/// (and the pages `prepare` gives them).
|
||||
fn keeps(params: &Params, words: &[u32], record: &Record) -> bool {
|
||||
let (key, a) = (record.key, record.a);
|
||||
if key[3] < 0 || a[1] == 0 || !near(params, key[0], key[2]) {
|
||||
if key[3] < 0 || a[1] == 0 || (a[3] & FADING) != 0 || !near(params, key[0], key[2]) {
|
||||
return false;
|
||||
}
|
||||
let c: [u32; 3] = std::array::from_fn(|i| key[i].wrapping_sub(params.first[i]) as u32);
|
||||
@@ -1099,10 +1185,13 @@ mod tests {
|
||||
Some([min, max])
|
||||
}
|
||||
|
||||
/// Ids, page counts and changes against a plain list of what each id holds:
|
||||
/// the lowest free id comes back, free ids at the end leave, counts follow
|
||||
/// moves (to pages past the last too), a move keeps the box, a free is a
|
||||
/// change, and more changes than updates take mark the whole table.
|
||||
/// Ids, page counts, flags and changes against a plain list of what each id
|
||||
/// holds: the lowest free id comes back, flagged only if inserted so, free
|
||||
/// ids at the end leave, counts follow moves (to pages past the last too), a
|
||||
/// move keeps the box and the flag, a free is a change, a flag set changes
|
||||
/// its record only when it differs, the flagged ones are counted through
|
||||
/// inserts, flags, removals and clears, and more changes than updates take
|
||||
/// mark the whole table.
|
||||
#[test]
|
||||
fn records_keep_ids_page_counts_and_moves() {
|
||||
let mut records = Records::default();
|
||||
@@ -1140,7 +1229,7 @@ mod tests {
|
||||
};
|
||||
let mut rng = Rng(0x9E37_79B9_7F4A_7C15);
|
||||
// What each id holds; `None`: a free id.
|
||||
let mut model: Vec<Option<Placed>> = vec![Some(((2, 0, 0), 1, 0, 3, 11))];
|
||||
let mut model: Vec<Option<Placed>> = vec![Some(((2, 0, 0), 1, 0, 3, 11, false))];
|
||||
for step in 0..4_000 {
|
||||
let live: Vec<u32> = (0..model.len() as u32)
|
||||
.filter(|&id| model[id as usize].is_some())
|
||||
@@ -1149,20 +1238,22 @@ mod tests {
|
||||
rng.below(4 + step / 500),
|
||||
u64::from(rng.below(1 << 20)) * 256,
|
||||
);
|
||||
match rng.below(5) {
|
||||
let dirty = records.dirty.len();
|
||||
match rng.below(6) {
|
||||
op if op < 2 || live.is_empty() => {
|
||||
let key = (rng.range(-9, 9), rng.range(0, 23), rng.range(-9, 9));
|
||||
let (quads, boxed) = (1 + rng.below(500), rng.below(1 << 30));
|
||||
let fading = rng.below(4) == 0;
|
||||
let lowest = model
|
||||
.iter()
|
||||
.position(Option::is_none)
|
||||
.unwrap_or(model.len());
|
||||
let record = Record::new(key, page, start, quads, boxed);
|
||||
let record = Record::new(key, page, start, quads, boxed).fading(fading);
|
||||
assert_eq!(records.insert(record) as usize, lowest);
|
||||
if lowest == model.len() {
|
||||
model.push(None);
|
||||
}
|
||||
model[lowest] = Some((key, page, start, quads, boxed));
|
||||
model[lowest] = Some((key, page, start, quads, boxed, fading));
|
||||
}
|
||||
op => {
|
||||
let id = live[rng.below(live.len() as u32) as usize];
|
||||
@@ -1170,6 +1261,12 @@ mod tests {
|
||||
if op < 4 {
|
||||
records.relocate(id, page, start);
|
||||
(held.1, held.2) = (page, start);
|
||||
} else if op == 4 {
|
||||
let on = rng.below(2) == 0;
|
||||
records.set_fading(id, on);
|
||||
let changed = usize::from(held.5 != on);
|
||||
assert_eq!(records.dirty.len(), dirty + changed, "step {step}");
|
||||
held.5 = on;
|
||||
} else {
|
||||
records.remove(id);
|
||||
// Marked: the GPU must have it free before the pass culls.
|
||||
@@ -1183,11 +1280,13 @@ mod tests {
|
||||
}
|
||||
assert_eq!(records.ids() as usize, model.len(), "step {step}");
|
||||
assert_eq!(records.live(), model.iter().flatten().count());
|
||||
let flagged = model.iter().flatten().filter(|held| held.5).count();
|
||||
assert_eq!(records.fading() as usize, flagged, "step {step}");
|
||||
let mut pages = vec![0; records.page_sections().len()];
|
||||
for (id, held) in model.iter().enumerate() {
|
||||
let record = held.map(|(key, page, start, quads, boxed)| {
|
||||
let record = held.map(|(key, page, start, quads, boxed, fading)| {
|
||||
pages[page as usize] += 1;
|
||||
Record::new(key, page, start, quads, boxed)
|
||||
Record::new(key, page, start, quads, boxed).fading(fading)
|
||||
});
|
||||
assert_eq!(
|
||||
records.at(id as u32),
|
||||
@@ -1204,16 +1303,17 @@ mod tests {
|
||||
let (mut each, mut all) = (Records::default(), Records::default());
|
||||
for n in 0..1_000 {
|
||||
let (key, page, start) = ((n % 31, n % 24, n / 31), n as u32 % 3, n as u64 * 256);
|
||||
let record = Record::new(key, page, start, 1, 0);
|
||||
let record = Record::new(key, page, start, 1, 0).fading(n % 7 == 0);
|
||||
assert_eq!(each.insert(record), all.insert(record));
|
||||
}
|
||||
let gone: Vec<u32> = (0..1_000).filter(|id| id % 3 != 1 || *id >= 900).collect();
|
||||
let counts = |r: &Records| (r.ids(), r.live(), r.fading());
|
||||
for ids in [&[1u32, 4, 898][..], &gone[..]] {
|
||||
for &id in ids {
|
||||
each.remove(id);
|
||||
}
|
||||
all.remove_all(ids.iter().copied());
|
||||
assert_eq!((all.ids(), all.live()), (each.ids(), each.live()));
|
||||
assert_eq!(counts(&all), counts(&each));
|
||||
assert_eq!(all.page_sections(), each.page_sections());
|
||||
assert_eq!(free_ids(&all), free_ids(&each));
|
||||
assert_eq!(all.dirty, each.dirty);
|
||||
@@ -1228,8 +1328,9 @@ mod tests {
|
||||
assert_eq!((all.ids(), all.live(), all.free.len()), (0, 0, 0));
|
||||
assert!(all.page_sections().iter().all(|&n| n == 0));
|
||||
|
||||
assert!(records.fading() > 0);
|
||||
records.clear();
|
||||
assert_eq!((records.ids(), records.live()), (0, 0));
|
||||
assert_eq!((records.ids(), records.live(), records.fading()), (0, 0, 0));
|
||||
assert!(records.page_sections().is_empty() && records.dirty.is_empty());
|
||||
for x in 0..DIRTY_LIMIT as i32 {
|
||||
records.insert(Record::new((x, 0, 0), 0, 0, 1, 0));
|
||||
@@ -1360,6 +1461,7 @@ mod tests {
|
||||
("UNBOUNDED", u64::from(UNBOUNDED)),
|
||||
("REACH", u64::from(REACH)),
|
||||
("SKY", u64::from(SKY)),
|
||||
("FADING", u64::from(FADING)),
|
||||
] {
|
||||
assert_eq!(constant(name), value, "{name}");
|
||||
}
|
||||
@@ -1784,7 +1886,9 @@ mod tests {
|
||||
/// reached or not: the pass reads the copy it holds when a frame brings the
|
||||
/// same graph (once through a bind group made anew), sends a new one after
|
||||
/// a frame the CPU draws, and makes its copy anew for one too large for its
|
||||
/// room.
|
||||
/// room. A fifth of the sections fade, flagged anew before each case
|
||||
/// (`FADING`, sent as updates or with the whole table): the pass leaves
|
||||
/// them to the CPU.
|
||||
#[test]
|
||||
fn the_gpu_draws_what_the_integer_test_keeps() {
|
||||
on_each_device(draws_match);
|
||||
@@ -1792,11 +1896,14 @@ mod tests {
|
||||
|
||||
fn draws_match(device: &wgpu::Device, queue: &Queue) {
|
||||
let mut rng = Rng(0x2545_F491_4F6C_DD1D);
|
||||
// The flags have their own sequence: the cases are otherwise as before.
|
||||
let mut flags = Rng(0x9E37_79B9_7F4A_7C15);
|
||||
let (min_y, height) = (-64, 24);
|
||||
let mut gpu = GpuCulling::new(device).expect("the pass");
|
||||
let mut uploads = Uploads::new(device);
|
||||
let mut held: BTreeMap<u32, Placed> = BTreeMap::new();
|
||||
let (mut camera, mut compared, mut culled) = (DVec3::ZERO, 0, 0);
|
||||
// Fading sections the frustum and the graph keep, left to the CPU.
|
||||
let (mut camera, mut compared, mut culled, mut faded) = (DVec3::ZERO, 0, 0, 0);
|
||||
let mut words = Vec::new();
|
||||
// Cave culling's graph while a case has one (its generation, from x and
|
||||
// z, radius, height and whether its search reached the sky) and its bits.
|
||||
@@ -1897,7 +2004,8 @@ mod tests {
|
||||
.records
|
||||
.insert(Record::new(key, page, start, quads, boxed));
|
||||
assert!(
|
||||
held.insert(id, (key, page, start, quads, boxed)).is_none(),
|
||||
held.insert(id, (key, page, start, quads, boxed, false))
|
||||
.is_none(),
|
||||
"id {id} twice"
|
||||
);
|
||||
};
|
||||
@@ -1912,6 +2020,13 @@ mod tests {
|
||||
place(&mut gpu, &mut held, &mut rng);
|
||||
}
|
||||
}
|
||||
// A fifth of the sections fade: the flags that change go up as
|
||||
// updates, or with the whole table (cases 4 and 18), and through
|
||||
// case 7's frame the CPU draws.
|
||||
for (&id, placed) in held.iter_mut() {
|
||||
placed.5 = flags.below(5) == 0;
|
||||
gpu.records.set_fading(id, placed.5);
|
||||
}
|
||||
let whole = gpu.records.all_dirty;
|
||||
let mut encoder = device.create_command_encoder(&Default::default());
|
||||
let input = FrameInputs {
|
||||
@@ -1947,10 +2062,12 @@ mod tests {
|
||||
let mut params = tables(&input, &mut words).expect("the planes fit");
|
||||
params.pages = gpu.pass_pages;
|
||||
let mut expected = Vec::new();
|
||||
for &(key, page, start, quads, boxed) in held.values() {
|
||||
for &(key, page, start, quads, boxed, fading) in held.values() {
|
||||
let record = Record::new(key, page, start, quads, boxed);
|
||||
let kept = keeps(¶ms, &words, &record);
|
||||
let kept = keeps(¶ms, &words, &record.fading(fading));
|
||||
let reached = reach.is_none_or(|r| r.contains(key));
|
||||
// In view, but fading: the CPU's.
|
||||
faded += usize::from(fading && reached && keeps(¶ms, &words, &record));
|
||||
if kept && let Some(r) = reach {
|
||||
graphed += 1;
|
||||
unreached += usize::from(!reached);
|
||||
@@ -1965,7 +2082,7 @@ mod tests {
|
||||
let origin = resident::origin(key, min_y, camera).as_vec3();
|
||||
let instance = super::super::section_instance(origin.to_array(), 0, 1.0);
|
||||
expected.push((page, start as u32, quads * 6, instance.map(f32::to_bits)));
|
||||
} else if in_view_distance((cx, cz), radius, key.0, key.2) {
|
||||
} else if !fading && in_view_distance((cx, cz), radius, key.0, key.2) {
|
||||
culled += 1;
|
||||
}
|
||||
}
|
||||
@@ -2012,8 +2129,10 @@ mod tests {
|
||||
// Not a comparison of empty lists, nor of a test that keeps everything.
|
||||
// The graphs leave out a real share of what the frustum keeps, and their
|
||||
// sky band keeps sections above a box in some cases and not in others.
|
||||
// The flags leave out about a fifth of what they would keep.
|
||||
assert!(compared > 2_000, "{compared} draws");
|
||||
assert!(culled > 2_000, "{culled} within the distance left out");
|
||||
assert!(faded * 10 > compared, "{faded} fading of {compared} drawn");
|
||||
assert!(
|
||||
unreached * 10 > graphed && unreached < graphed,
|
||||
"{unreached} of {graphed} in view unreached"
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
// them as the GPU schedules, and where faces of two sections meet at the same
|
||||
// depth the later draw keeps the pixel). Nothing here computes with floats: the
|
||||
// origins are the CPU's bits, copied, and the frustum test adds integers the
|
||||
// CPU computed.
|
||||
// CPU computed. `cull` leaves sections fading in or out to the CPU (`FADING`).
|
||||
|
||||
struct Params {
|
||||
// Ids to test, records `apply` writes, the arena pages the counts and
|
||||
@@ -45,7 +45,7 @@ struct Section {
|
||||
// free id).
|
||||
key: vec4<i32>,
|
||||
// The first vertex of its solid quads, its solid quads, its box
|
||||
// (gpu_culling.rs `rounded_box`), then a word unused here.
|
||||
// (gpu_culling.rs `rounded_box`), then its flags (`FADING`).
|
||||
a: vec4<u32>,
|
||||
}
|
||||
|
||||
@@ -91,6 +91,8 @@ const UNBOUNDED: u32 = 0x80000000u;
|
||||
// reached the box's top layer (the sky band).
|
||||
const REACH: u32 = 1u;
|
||||
const SKY: u32 = 2u;
|
||||
// In a section's `a.w`: it fades in or out, and the CPU draws it with its fade.
|
||||
const FADING: u32 = 1u;
|
||||
|
||||
// The count of `block`'s draws in `page` (`cull`), then where they start (`scan`).
|
||||
fn block_count(block: u32, page: u32) -> u32 {
|
||||
@@ -186,7 +188,8 @@ fn cull(@builtin(global_invocation_id) gid: vec3<u32>) {
|
||||
}
|
||||
runs[id] = 0u;
|
||||
let s = sections[id];
|
||||
if s.key.w < 0 || s.a.y == 0u || !near(s.key.x, s.key.z) || !reached(s.key.xyz) {
|
||||
if s.key.w < 0 || s.a.y == 0u || (s.a.w & FADING) != 0u || !near(s.key.x, s.key.z)
|
||||
|| !reached(s.key.xyz) {
|
||||
return;
|
||||
}
|
||||
let page = u32(s.key.w);
|
||||
|
||||
@@ -42,18 +42,32 @@ impl Output {
|
||||
}
|
||||
}
|
||||
|
||||
/// `HORIZON_HDR_OUTPUT`'s names, in order of preference.
|
||||
const NAMES: [(Output, &str); 2] = [(Output::Pq, "pq"), (Output::ScRgb, "scrgb")];
|
||||
|
||||
/// The HDR output `caps` can present: HDR10 where offered, else scRGB.
|
||||
/// `HORIZON_HDR_OUTPUT=pq` or `scrgb` allows only that one.
|
||||
pub fn output(caps: &wgpu::SurfaceCapabilities) -> Option<Output> {
|
||||
pick(caps, std::env::var("HORIZON_HDR_OUTPUT").ok().as_deref())
|
||||
}
|
||||
fn pick(caps: &wgpu::SurfaceCapabilities, only: Option<&str>) -> Option<Output> {
|
||||
[(Output::Pq, "pq"), (Output::ScRgb, "scrgb")]
|
||||
NAMES
|
||||
.into_iter()
|
||||
.filter(|(_, name)| only.is_none_or(|o| o == *name))
|
||||
.map(|(output, _)| output)
|
||||
.find(|o| caps.color_spaces(o.format()).contains(o.space()))
|
||||
}
|
||||
/// The HDR output an offscreen renderer (`--offscreen`) offers: it has no display to ask, so
|
||||
/// only the one `HORIZON_HDR_OUTPUT` names, for HDR screenshots without an HDR display.
|
||||
pub fn offscreen_output() -> Option<Output> {
|
||||
named(std::env::var("HORIZON_HDR_OUTPUT").ok().as_deref())
|
||||
}
|
||||
fn named(name: Option<&str>) -> Option<Output> {
|
||||
NAMES
|
||||
.into_iter()
|
||||
.find(|(_, n)| name == Some(*n))
|
||||
.map(|(output, _)| output)
|
||||
}
|
||||
|
||||
struct Targets {
|
||||
size: [u32; 2],
|
||||
@@ -637,7 +651,7 @@ fn scene_gain(peak: f32, paper_white: f32) -> f32 {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{Output, pick};
|
||||
use super::{Output, named, pick};
|
||||
use wgpu::{SurfaceColorSpaces as S, TextureFormat as F};
|
||||
|
||||
#[test]
|
||||
@@ -687,6 +701,14 @@ mod tests {
|
||||
assert_eq!(pick(&scrgb, Some("pq")), None);
|
||||
assert_eq!(pick(&caps(&[(F::Bgra8UnormSrgb, S::SRGB)]), None), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn offscreen_offers_only_the_named_output() {
|
||||
assert_eq!(named(Some("pq")), Some(Output::Pq));
|
||||
assert_eq!(named(Some("scrgb")), Some(Output::ScRgb));
|
||||
assert_eq!(named(Some("hdr10")), None);
|
||||
assert_eq!(named(None), None);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -59,6 +59,25 @@ fn chosen_cells(
|
||||
chosen.unwrap_or(d.cells)
|
||||
}
|
||||
|
||||
/// `[shadow]` with the option values `constants`: none while its `option` is off, else the
|
||||
/// resolution and distance its `resolution_option` and `distance_option` pick.
|
||||
fn chosen_shadow(
|
||||
s: &horizon_shader_api::manifest::Shadow,
|
||||
options: &[horizon_shader_api::manifest::PackOption],
|
||||
constants: &[(String, f64)],
|
||||
) -> Option<horizon_shader_api::manifest::Shadow> {
|
||||
let number = |id: Option<&String>| {
|
||||
let option = options.iter().find(|o| Some(&o.id) == id)?;
|
||||
let (_, value) = constants.iter().find(|(k, _)| *k == option.id)?;
|
||||
option.kind.number(*value)
|
||||
};
|
||||
option_on(constants, s.option.as_ref()).then(|| horizon_shader_api::manifest::Shadow {
|
||||
resolution: number(s.resolution_option.as_ref()).map_or(s.resolution, |r| r as u32),
|
||||
distance: number(s.distance_option.as_ref()).map_or(s.distance, |d| d as f32),
|
||||
..s.clone()
|
||||
})
|
||||
}
|
||||
|
||||
impl NativePack {
|
||||
/// The pack of the checked stages `report` with the option values `constants`, drawing
|
||||
/// onto the world's targets as `terrain` describes; the sky reads the terrain's group 0.
|
||||
@@ -74,8 +93,12 @@ impl NativePack {
|
||||
) -> Result<(Self, Vec<String>), String> {
|
||||
let (globals, format) = (terrain.globals, terrain.format);
|
||||
let textures = super::native_post::pack_textures(device, queue, &report);
|
||||
let settings = report
|
||||
// `[shadow]`, unless its option is off, at the size its options pick.
|
||||
let chosen = report
|
||||
.shadow
|
||||
.as_ref()
|
||||
.and_then(|s| chosen_shadow(s, &report.manifest.options, constants));
|
||||
let settings = chosen
|
||||
.as_ref()
|
||||
.map(|settings| super::native_shadow::fitted(device, settings));
|
||||
let mut frame = NativeFrame::new(device, settings.as_ref(), textures, lights, terrain.pbr);
|
||||
@@ -103,8 +126,7 @@ impl NativePack {
|
||||
report.shadow.is_some(),
|
||||
)
|
||||
});
|
||||
let shadow = report
|
||||
.shadow
|
||||
let shadow = chosen
|
||||
.as_ref()
|
||||
.map(|s| {
|
||||
let vertex = report.stages.iter().find(|s| s.kind == StageKind::Vertex);
|
||||
@@ -240,3 +262,61 @@ impl NativePack {
|
||||
|| self.post.is_some()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::chosen_shadow;
|
||||
use horizon_shader_api::manifest::{OptionKind, PackOption, Shadow};
|
||||
|
||||
fn option(id: &str, kind: OptionKind) -> PackOption {
|
||||
PackOption {
|
||||
id: id.into(),
|
||||
name: id.into(),
|
||||
description: String::new(),
|
||||
kind,
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_shadow_map_follows_its_options() {
|
||||
let options = [
|
||||
option("shadows", OptionKind::Bool { default: true }),
|
||||
option(
|
||||
"quality",
|
||||
OptionKind::Choice {
|
||||
values: vec!["1024".into(), "4096".into()],
|
||||
default: 0,
|
||||
},
|
||||
),
|
||||
option(
|
||||
"reach",
|
||||
OptionKind::Int {
|
||||
default: 96,
|
||||
min: 32,
|
||||
max: 512,
|
||||
},
|
||||
),
|
||||
];
|
||||
let shadow = Shadow {
|
||||
option: Some("shadows".into()),
|
||||
resolution_option: Some("quality".into()),
|
||||
distance_option: Some("reach".into()),
|
||||
..Shadow::default()
|
||||
};
|
||||
let values = |on: f64, quality: f64, reach: f64| {
|
||||
[("shadows", on), ("quality", quality), ("reach", reach)].map(|(k, v)| (k.into(), v))
|
||||
};
|
||||
let size = |values: &[(String, f64)]| {
|
||||
chosen_shadow(&shadow, &options, values).map(|s| (s.resolution, s.distance))
|
||||
};
|
||||
assert_eq!(size(&values(1.0, 1.0, 200.0)), Some((4096, 200.0)));
|
||||
assert_eq!(size(&values(1.0, 0.0, 64.0)), Some((1024, 64.0)));
|
||||
assert_eq!(size(&values(0.0, 1.0, 200.0)), None);
|
||||
// Without the options' keys: the manifest's own numbers, always drawn.
|
||||
assert_eq!(
|
||||
chosen_shadow(&Shadow::default(), &options, &values(0.0, 1.0, 200.0))
|
||||
.map(|s| (s.resolution, s.distance)),
|
||||
Some((2048, 128.0))
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -76,14 +76,14 @@ pub struct WorldDrawn<'a> {
|
||||
/// the run's first vertex and the entity, `(1 << 32) | id` for a mob or a player and
|
||||
/// `(2 << 32) | id` for a dropped item (their entity ids), 0 for anything else. A run lasts
|
||||
/// until the next. Unlike `spans`, whose ids name a type, these follow one entity from
|
||||
/// frame to frame (API @API:world_drawn_motion@).
|
||||
/// frame to frame (API 371).
|
||||
pub motion: &'a [(u32, u64)],
|
||||
/// The shared atlas entity UVs point into.
|
||||
pub atlas: Option<&'a wgpu::Texture>,
|
||||
/// Quad indices (0 1 2 0 2 3 for each 4 vertices), for as many quads as `entities` holds.
|
||||
pub quad_indices: &'a wgpu::Buffer,
|
||||
/// The block textures the terrain samples, for drawing blocks with the player's own
|
||||
/// textures (`native_block_sprites` says where a block's are). API @API:native_block_sprites@.
|
||||
/// textures (`native_block_sprites` says where a block's are). API 380.
|
||||
pub block_sprites: BlockSpriteArrays<'a>,
|
||||
}
|
||||
|
||||
@@ -154,7 +154,7 @@ pub fn native_world_drawn(world: &mut WorldDrawn<'_>) {
|
||||
}
|
||||
|
||||
/// The first-person hand is drawn (see [`HandDrawn`]), on every frame [`native_world_drawn`]
|
||||
/// runs, with no hand too. API @API:hand_drawn@.
|
||||
/// runs, with no hand too. API 364.
|
||||
#[inline(never)]
|
||||
pub fn native_hand_drawn(hand: &mut HandDrawn<'_>) {
|
||||
generated::dispatch_hand_drawn(RENDERERS.get().map_or(&[], |renderers| renderers), hand);
|
||||
|
||||
@@ -806,12 +806,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn what_the_camera_stands_on_is_inside_the_shadow_cameras_depth() {
|
||||
let settings = Settings {
|
||||
resolution: 2048,
|
||||
distance: 128.0,
|
||||
solid_materials: Vec::new(),
|
||||
};
|
||||
let shadow = camera(&settings);
|
||||
let shadow = camera(&Settings::default());
|
||||
let (view, projection) = super::super::pack_uniforms::shadow_camera(
|
||||
glam::Vec3::new(0.3, 0.9, 0.0).normalize(),
|
||||
glam::DVec3::new(-2064.5, 246.0, -4304.5),
|
||||
@@ -827,11 +822,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn the_centre_stays_near_the_player_on_both_sides_of_zero() {
|
||||
let shadow = camera(&Settings {
|
||||
resolution: 2048,
|
||||
distance: 128.0,
|
||||
solid_materials: Vec::new(),
|
||||
});
|
||||
let shadow = camera(&Settings::default());
|
||||
let light = glam::Vec3::Y;
|
||||
for x in [5.5, -5.5, -2064.5, 2064.5] {
|
||||
let camera = glam::DVec3::new(x, 64.0, x);
|
||||
|
||||
@@ -26,6 +26,37 @@ impl PackAtlas {
|
||||
split: u32,
|
||||
layers: u32,
|
||||
sprite: u32,
|
||||
) -> Option<Self> {
|
||||
Self::with_levels(
|
||||
device,
|
||||
encoder,
|
||||
arrays,
|
||||
split,
|
||||
layers,
|
||||
sprite,
|
||||
arrays[0].mip_level_count(),
|
||||
)
|
||||
}
|
||||
|
||||
/// Encoded material channels must select an existing texel, including at distance.
|
||||
pub fn material(
|
||||
device: &wgpu::Device,
|
||||
encoder: &mut wgpu::CommandEncoder,
|
||||
arrays: &[wgpu::Texture],
|
||||
split: u32,
|
||||
layers: u32,
|
||||
) -> Option<Self> {
|
||||
Self::with_levels(device, encoder, arrays, split, layers, arrays[0].width(), 1)
|
||||
}
|
||||
|
||||
fn with_levels(
|
||||
device: &wgpu::Device,
|
||||
encoder: &mut wgpu::CommandEncoder,
|
||||
arrays: &[wgpu::Texture],
|
||||
split: u32,
|
||||
layers: u32,
|
||||
sprite: u32,
|
||||
levels: u32,
|
||||
) -> Option<Self> {
|
||||
let layers = layers.max(1);
|
||||
let columns = (f64::from(layers).sqrt().ceil() as u32).max(1);
|
||||
@@ -35,7 +66,7 @@ impl PackAtlas {
|
||||
return None;
|
||||
}
|
||||
// Levels past a sprite's single pixel would mix neighbours: stop there.
|
||||
let levels = arrays[0].mip_level_count().min(sprite.ilog2() + 1);
|
||||
let levels = levels.min(sprite.ilog2() + 1);
|
||||
let texture = device.create_texture(&wgpu::TextureDescriptor {
|
||||
label: Some("Shader pack block atlas"),
|
||||
size: wgpu::Extent3d {
|
||||
@@ -65,6 +96,17 @@ impl PackAtlas {
|
||||
Some(atlas)
|
||||
}
|
||||
|
||||
/// The table flat terrain reads (`hz_sprite_rects`): per layer, its sprite's top left corner
|
||||
/// (x | y << 16) and side, in atlas pixels.
|
||||
pub fn rects_table(&self) -> Vec<u32> {
|
||||
(0..self.columns * self.texture.height() / self.sprite)
|
||||
.flat_map(|layer| {
|
||||
let (x, y) = (layer % self.columns, layer / self.columns);
|
||||
[(x * self.sprite) | ((y * self.sprite) << 16), self.sprite]
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// The atlas's size in pixels (`atlasSize`).
|
||||
pub fn size(&self) -> [u32; 2] {
|
||||
[self.texture.width(), self.texture.height()]
|
||||
@@ -173,7 +215,8 @@ impl PackAtlas {
|
||||
// vertices (`TerrainVertex`, six words each).
|
||||
declarations.push_str(
|
||||
"layout(set = 3, binding = 0) readonly buffer HzBlockIds { int hz_block_ids[]; };\n\
|
||||
layout(set = 3, binding = 1) readonly buffer HzVertices { uint hz_vertices[]; };\n",
|
||||
layout(set = 3, binding = 1) readonly buffer HzVertices { uint hz_vertices[]; };\n\
|
||||
layout(set = 3, binding = 2) readonly buffer HzSpriteRects { uvec2 hz_sprite_rects[]; };\n",
|
||||
);
|
||||
"hz_slot_origins[hz_block_slots[uint(gl_VertexIndex) >> 8u]]"
|
||||
} else {
|
||||
@@ -181,11 +224,29 @@ impl PackAtlas {
|
||||
"hz_v_origin"
|
||||
};
|
||||
let [width, height] = self.size();
|
||||
let scale = [
|
||||
self.sprite as f32 / width as f32,
|
||||
self.sprite as f32 / height as f32,
|
||||
];
|
||||
// A sprite's cell in its own sides, and the share of the atlas a side is: from the table
|
||||
// in flat draws (`rects_table`), from the grid in others.
|
||||
let columns = self.columns;
|
||||
let (cell, side, scale) = if flat {
|
||||
(
|
||||
"uvec2 hz_rect = hz_sprite_rects[hz_layer];\n \
|
||||
hz_cell = vec2(float(hz_rect.x & 65535u), float(hz_rect.x >> 16u)) / float(hz_rect.y);\n "
|
||||
.to_owned(),
|
||||
"float(hz_rect.y)",
|
||||
[1.0 / width as f32, 1.0 / height as f32],
|
||||
)
|
||||
} else {
|
||||
(
|
||||
format!(
|
||||
"hz_cell = vec2(float(hz_layer % {columns}u), float(hz_layer / {columns}u));\n "
|
||||
),
|
||||
"1.0",
|
||||
[
|
||||
self.sprite as f32 / width as f32,
|
||||
self.sprite as f32 / height as f32,
|
||||
],
|
||||
)
|
||||
};
|
||||
// UVs past a sprite (models up to 2, distant tiles) cannot repeat in an atlas: clamped.
|
||||
// The colour's alpha holds HDR's emission level (`mesher::EMISSION_BITS`): packs get 1 unless separate_ao.
|
||||
let color_a = if self.separate_ao {
|
||||
@@ -196,8 +257,8 @@ impl PackAtlas {
|
||||
let body = format!(
|
||||
" vec4 hz_origin = {origin};\n \
|
||||
uint hz_layer = hz_v_layer & 32767u;\n \
|
||||
hz_cell = vec2(float(hz_layer % {columns}u), float(hz_layer / {columns}u));\n \
|
||||
hz_scale = vec2({:?}, {:?});\n \
|
||||
{cell}\
|
||||
hz_scale = vec2({:?}, {:?}) * {side};\n \
|
||||
hz_Vertex = vec4(hz_v_pos + hz_origin.xyz, 1.0);\n \
|
||||
hz_uv_scale = hz_origin.w > 0.0 ? uintBitsToFloat(floatBitsToUint(hz_origin.w) & 0xff800000u) : fract(abs(hz_origin.w));\n \
|
||||
hz_mid = vec2(0.5);\n \
|
||||
@@ -252,6 +313,7 @@ impl PackAtlas {
|
||||
.collect(),
|
||||
after: String::new(),
|
||||
alpha_test: None,
|
||||
item_id_declared: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,7 +183,7 @@ fn sample(
|
||||
}],
|
||||
vec![storage(0), storage(1)],
|
||||
vec![],
|
||||
vec![storage(0), storage(1)],
|
||||
vec![storage(0), storage(1), storage(2)],
|
||||
];
|
||||
let layouts: Vec<_> = entries
|
||||
.iter()
|
||||
@@ -268,11 +268,15 @@ fn sample(
|
||||
bytemuck::cast_slice(vertices),
|
||||
wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::VERTEX,
|
||||
);
|
||||
let rects = buffer(
|
||||
bytemuck::cast_slice(&atlas.rects_table()),
|
||||
wgpu::BufferUsages::STORAGE,
|
||||
);
|
||||
let bindings = [
|
||||
vec![(0, &uniform)],
|
||||
vec![(0, &slots), (1, &origin)],
|
||||
vec![],
|
||||
vec![(0, &ids), (1, &data)],
|
||||
vec![(0, &ids), (1, &data), (2, &rects)],
|
||||
];
|
||||
let groups: Vec<_> = bindings
|
||||
.iter()
|
||||
|
||||
@@ -58,7 +58,8 @@ impl EntitySpan {
|
||||
}
|
||||
}
|
||||
|
||||
/// `HzDraw`'s size: `renderStage`, `entityId`, `blockEntityId`, a pad, `entityColor`.
|
||||
/// `HzDraw`'s size: `renderStage`, `entityId`, `blockEntityId`, `currentRenderedItemId`,
|
||||
/// `entityColor`.
|
||||
const SIZE: u32 = 32;
|
||||
|
||||
pub(super) struct DrawUniforms {
|
||||
@@ -73,8 +74,10 @@ impl DrawUniforms {
|
||||
let mut contents = vec![0u8; stride as usize * RENDER_STAGES.len()];
|
||||
for (i, slot) in contents.chunks_mut(stride as usize).enumerate() {
|
||||
slot[..4].copy_from_slice(&(i as i32).to_le_bytes());
|
||||
// `blockEntityId` outside block entities, as Iris has it.
|
||||
// `blockEntityId` outside block entities, as Iris has it; `currentRenderedItemId`
|
||||
// outside items, as Iris 1.11.7 gives it to terrain, water and the sky (observed).
|
||||
slot[8..12].copy_from_slice(&(-1i32).to_le_bytes());
|
||||
slot[12..16].copy_from_slice(&(-1i32).to_le_bytes());
|
||||
}
|
||||
let buffer = wgpu::util::DeviceExt::create_buffer_init(
|
||||
device,
|
||||
|
||||
@@ -101,6 +101,7 @@ pub fn inputs() -> horizon_shaders::GbuffersInputs {
|
||||
op: ">",
|
||||
reference: 0.1,
|
||||
}),
|
||||
item_id_declared: false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,6 +163,7 @@ pub fn cloud_inputs() -> horizon_shaders::GbuffersInputs {
|
||||
.collect(),
|
||||
after: String::new(),
|
||||
alpha_test: None,
|
||||
item_id_declared: false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -426,7 +428,9 @@ impl PackEntities {
|
||||
}),
|
||||
};
|
||||
let pack = program.is_some_and(|p| drawn[p]) && !span.hidden;
|
||||
let casts = part == Part::Plain && program.is_some_and(|p| shadow.cast(&span, p));
|
||||
// Portal faces cast too (a pack's shadow pass sees block entities whole, as Iris
|
||||
// draws them); beams do not.
|
||||
let casts = part != Part::Beam && program.is_some_and(|p| shadow.cast(&span, p));
|
||||
if !pack && !span.hidden {
|
||||
extend_without_portals(rest, run);
|
||||
}
|
||||
@@ -1032,6 +1036,57 @@ mod gpu_span_tests {
|
||||
assert_eq!(skin.spans.len(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn end_portal_faces_reach_the_shadow_pass_with_their_block_entity() {
|
||||
let instance = crate::gfx::test_gpu::instance();
|
||||
let Ok(adapter) = pollster::block_on(instance.request_adapter(&Default::default())) else {
|
||||
return;
|
||||
};
|
||||
let Ok((device, queue)) = pollster::block_on(adapter.request_device(&Default::default()))
|
||||
else {
|
||||
return;
|
||||
};
|
||||
let layout = super::super::pack_draw::DrawUniforms::new(&device);
|
||||
let mut geometry = PackEntities::new(&device, &layout.layout);
|
||||
// One block entity: a plain face, then an End portal face (overlay layer 9).
|
||||
let cpu: Vec<Vertex> = [0, 0, 0, 0, 9, 9, 9, 9]
|
||||
.into_iter()
|
||||
.map(|layer| Vertex {
|
||||
layer,
|
||||
..bytemuck::Zeroable::zeroed()
|
||||
})
|
||||
.collect();
|
||||
let spans = [EntitySpan {
|
||||
start: 0,
|
||||
id: 99,
|
||||
stage: render_stage("BLOCK_ENTITIES"),
|
||||
..Default::default()
|
||||
}];
|
||||
let mut rest = Vec::new();
|
||||
geometry.prepare(
|
||||
&device,
|
||||
&queue,
|
||||
&layout.layout,
|
||||
&cpu,
|
||||
&spans,
|
||||
[true; PROGRAMS],
|
||||
([0.; 4], [1; 2]),
|
||||
Casters {
|
||||
blocks: true,
|
||||
..Default::default()
|
||||
},
|
||||
&mut rest,
|
||||
None,
|
||||
);
|
||||
assert_eq!(
|
||||
(geometry.draws.iter())
|
||||
.map(|d| (d.portal, d.shadow))
|
||||
.collect::<Vec<_>>(),
|
||||
[(false, true), (true, true)],
|
||||
"the portal face casts as its block entity does"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn posed_and_cpu_draws_keep_offsets_uniforms_and_special_fallbacks() {
|
||||
let instance = crate::gfx::test_gpu::instance();
|
||||
|
||||
@@ -13,9 +13,14 @@ const HAND_DEPTH: f32 = 0.125;
|
||||
/// `HzHand`: the hand's projection and its inverse.
|
||||
const UNIFORM: u64 = 2 * 64;
|
||||
|
||||
/// `HzDraw`'s size (pack_draw.rs).
|
||||
const SLOT: u64 = 32;
|
||||
|
||||
/// What `gbuffers_hand` reads: the entity inputs, and the hand's projection from set 1.
|
||||
pub fn inputs() -> horizon_shaders::GbuffersInputs {
|
||||
let mut inputs = super::pack_entities::inputs();
|
||||
// Iris 1.11.7 declares `currentRenderedItemId` in the hand's programs (observed).
|
||||
inputs.item_id_declared = true;
|
||||
inputs.declarations.push_str(
|
||||
"layout(set = 1, binding = 1) uniform HzHand { mat4 hz_hand_projection; mat4 hz_hand_projection_inverse; };\n",
|
||||
);
|
||||
@@ -45,10 +50,17 @@ pub struct PackHand {
|
||||
capacity: u32,
|
||||
/// Quads uploaded this frame.
|
||||
pub quads: u32,
|
||||
/// `HzDraw` (set 2) of each run: the arm or one held item, and its `currentRenderedItemId`.
|
||||
slots: wgpu::Buffer,
|
||||
pub slot_group: wgpu::BindGroup,
|
||||
stride: u64,
|
||||
/// This frame's runs: first quad, quads, and the dynamic offset of their slot.
|
||||
pub runs: Vec<(u32, u32, u32)>,
|
||||
}
|
||||
|
||||
impl PackHand {
|
||||
pub fn new(device: &wgpu::Device) -> Self {
|
||||
/// `draws`: the layout of `HzDraw` (pack_draw.rs).
|
||||
pub fn new(device: &wgpu::Device, draws: &wgpu::BindGroupLayout) -> Self {
|
||||
let entry = |binding, ty| wgpu::BindGroupLayoutEntry {
|
||||
binding,
|
||||
visibility: wgpu::ShaderStages::VERTEX,
|
||||
@@ -74,6 +86,28 @@ impl PackHand {
|
||||
});
|
||||
let capacity = 256;
|
||||
let (vertices, group) = Self::vertex_buffer(device, &layout, &uniform, capacity);
|
||||
let stride = SLOT.max(u64::from(
|
||||
device.limits().min_uniform_buffer_offset_alignment,
|
||||
));
|
||||
// The arm and the two hands' items: a few runs a frame.
|
||||
let slots = device.create_buffer(&wgpu::BufferDescriptor {
|
||||
label: Some("Shader pack hand draws"),
|
||||
size: SLOTS * stride,
|
||||
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
|
||||
mapped_at_creation: false,
|
||||
});
|
||||
let slot_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||
label: Some("Shader pack hand draws"),
|
||||
layout: draws,
|
||||
entries: &[wgpu::BindGroupEntry {
|
||||
binding: 0,
|
||||
resource: wgpu::BindingResource::Buffer(wgpu::BufferBinding {
|
||||
buffer: &slots,
|
||||
offset: 0,
|
||||
size: wgpu::BufferSize::new(SLOT),
|
||||
}),
|
||||
}],
|
||||
});
|
||||
Self {
|
||||
indices: super::pack_entities::quad_indices(device, capacity),
|
||||
layout,
|
||||
@@ -82,6 +116,10 @@ impl PackHand {
|
||||
group,
|
||||
capacity,
|
||||
quads: 0,
|
||||
slots,
|
||||
slot_group,
|
||||
stride,
|
||||
runs: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,18 +154,31 @@ impl PackHand {
|
||||
(buffer, group)
|
||||
}
|
||||
|
||||
/// Uploads this frame's hand and its projection.
|
||||
/// Uploads this frame's hand, its projection, and the `HzDraw` of each run `items` starts
|
||||
/// (first vertex, `currentRenderedItemId`; the slots past [`SLOTS`] share the last).
|
||||
pub fn prepare(
|
||||
&mut self,
|
||||
device: &wgpu::Device,
|
||||
queue: &wgpu::Queue,
|
||||
hand: &[Vertex],
|
||||
items: &[(u32, i32)],
|
||||
projection: Mat4,
|
||||
) {
|
||||
self.quads = (hand.len() / 4) as u32;
|
||||
self.runs.clear();
|
||||
if self.quads == 0 {
|
||||
return;
|
||||
}
|
||||
let mut contents = Vec::new();
|
||||
for (start, quads, id) in runs(self.quads, items) {
|
||||
let slot = (self.runs.len() as u64).min(SLOTS - 1);
|
||||
if slot as usize == self.runs.len() {
|
||||
contents.extend_from_slice(&draw_slot(id));
|
||||
contents.resize(((slot + 1) * self.stride) as usize, 0);
|
||||
}
|
||||
self.runs.push((start, quads, (slot * self.stride) as u32));
|
||||
}
|
||||
queue.write_buffer(&self.slots, 0, &contents);
|
||||
if self.quads > self.capacity {
|
||||
self.capacity = self.quads.next_power_of_two();
|
||||
(self.vertices, self.group) =
|
||||
@@ -144,10 +195,54 @@ impl PackHand {
|
||||
}
|
||||
}
|
||||
|
||||
/// The hand's runs a frame keeps slots for.
|
||||
const SLOTS: u64 = 8;
|
||||
|
||||
/// `HzDraw` of a hand run: `renderStage` the solid hand's, `blockEntityId` -1 as outside block
|
||||
/// entities, and `currentRenderedItemId`.
|
||||
fn draw_slot(id: i32) -> [u8; SLOT as usize] {
|
||||
let mut bytes = [0u8; SLOT as usize];
|
||||
let stage = horizon_shaders::render_stage("HAND_SOLID") as i32;
|
||||
bytes[0..4].copy_from_slice(&stage.to_le_bytes());
|
||||
bytes[8..12].copy_from_slice(&(-1i32).to_le_bytes());
|
||||
bytes[12..16].copy_from_slice(&id.to_le_bytes());
|
||||
bytes
|
||||
}
|
||||
|
||||
/// The runs of `quads` quads that `items` starts (first vertex, id), as first quad, quads and
|
||||
/// id; geometry before the first start, or with no starts at all, reads 0, as the arm does.
|
||||
fn runs(quads: u32, items: &[(u32, i32)]) -> Vec<(u32, u32, i32)> {
|
||||
let mut starts: Vec<(u32, i32)> = vec![(0, 0)];
|
||||
for &(start, id) in items {
|
||||
let q = (start / 4).min(quads);
|
||||
match starts.last_mut() {
|
||||
Some(last) if last.0 == q => last.1 = id,
|
||||
_ => starts.push((q, id)),
|
||||
}
|
||||
}
|
||||
(0..starts.len())
|
||||
.map(|i| {
|
||||
let end = starts.get(i + 1).map_or(quads, |s| s.0);
|
||||
(starts[i].0, end - starts[i].0, starts[i].1)
|
||||
})
|
||||
.filter(|r| r.1 > 0)
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
/// Each item's quads draw with its id; geometry before the first item is the arm's (0).
|
||||
#[test]
|
||||
fn runs_split_the_hand_by_item() {
|
||||
assert_eq!(runs(3, &[]), [(0, 3, 0)]);
|
||||
assert_eq!(runs(5, &[(0, 11), (8, 65535)]), [(0, 2, 11), (2, 3, 65535)]);
|
||||
assert_eq!(runs(4, &[(4, 21)]), [(0, 1, 0), (1, 3, 21)]);
|
||||
// An item that drew nothing gives way to the next.
|
||||
assert_eq!(runs(2, &[(0, 11), (0, 22)]), [(0, 2, 22)]);
|
||||
}
|
||||
|
||||
/// The hand's window depth lies within `MC_HAND_DEPTH` of the middle (packs tell the hand
|
||||
/// apart by it), and x, y match the plain projection.
|
||||
#[test]
|
||||
|
||||
@@ -50,6 +50,7 @@ pub fn inputs() -> horizon_shaders::GbuffersInputs {
|
||||
.collect(),
|
||||
after,
|
||||
alpha_test: None,
|
||||
item_id_declared: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,259 @@
|
||||
//! Original synthetic material transport oracle; no external shader algorithms or assets.
|
||||
use super::*;
|
||||
use wgpu::util::DeviceExt;
|
||||
|
||||
#[test]
|
||||
#[ignore = "requires a host GPU; missing adapter is a failure"]
|
||||
fn terrain_material_samplers_preserve_surface_and_encoded_bytes() {
|
||||
let instance = crate::gfx::test_gpu::instance();
|
||||
let adapter = pollster::block_on(instance.request_adapter(&Default::default())).unwrap();
|
||||
eprintln!("Material transport GPU: {:?}", adapter.get_info());
|
||||
assert_ne!(adapter.get_info().device_type, wgpu::DeviceType::Cpu);
|
||||
let (device, queue) = pollster::block_on(adapter.request_device(&wgpu::DeviceDescriptor {
|
||||
required_limits: adapter.limits(),
|
||||
..Default::default()
|
||||
}))
|
||||
.unwrap();
|
||||
let root = std::env::temp_dir().join(format!("horizon-material-pack-{}", std::process::id()));
|
||||
std::fs::create_dir_all(root.join("shaders")).unwrap();
|
||||
std::fs::write(
|
||||
root.join("shaders/gbuffers_terrain.vsh"),
|
||||
"#version 120\nvoid main(){gl_Position=gl_Vertex;}",
|
||||
)
|
||||
.unwrap();
|
||||
std::fs::write(
|
||||
root.join("shaders/gbuffers_terrain.fsh"),
|
||||
r#"#version 120
|
||||
uniform sampler2D gtexture;
|
||||
uniform sampler2D normals;
|
||||
uniform sampler2D specular;
|
||||
void main() {
|
||||
int x = int(floor(gl_FragCoord.x));
|
||||
int layer = x - (x / 5) * 5;
|
||||
// Source coordinate (1.25,1.25): inside a texel, away from both its centre and boundary.
|
||||
vec2 uv = (vec2(float(layer - (layer / 3) * 3), float(layer / 3)) + 0.3125) / vec2(3.0, 2.0);
|
||||
if (x < 5) gl_FragData[0] = texture2DLod(specular, uv, 12.0);
|
||||
else if (x < 10) gl_FragData[0] = texture2DLod(normals, uv, 12.0);
|
||||
else gl_FragData[0] = texture2DLod(gtexture, uv, 0.0);
|
||||
}
|
||||
"#,
|
||||
)
|
||||
.unwrap();
|
||||
let (split, layers) = (2u32, 5u32);
|
||||
let mut encoder = device.create_command_encoder(&Default::default());
|
||||
let atlases: Vec<_> = (0..3)
|
||||
.map(|kind| {
|
||||
let side = if kind == 0 { 4 } else { 2 };
|
||||
let levels = if kind == 0 { 3 } else { 1 };
|
||||
let arrays: Vec<_> = (0..layers.div_ceil(split))
|
||||
.map(|array| {
|
||||
let count = (layers - array * split).min(split);
|
||||
let pixels: Vec<u8> = (0..count)
|
||||
.flat_map(|l| {
|
||||
let layer = (array * split + l) as u8;
|
||||
(0..levels).flat_map(move |level| {
|
||||
let edge = side >> level;
|
||||
(0..edge * edge).flat_map(move |pixel| {
|
||||
if level != 0 {
|
||||
// Sampling unused source mip levels must fail the oracle.
|
||||
[211, 212, 213, 214]
|
||||
} else {
|
||||
match kind {
|
||||
0 if layer == 3 => crate::sprites::NO_SPECULAR,
|
||||
0 => [
|
||||
17 + layer,
|
||||
if pixel % 2 == 0 { 0 } else { 240 },
|
||||
65,
|
||||
if pixel % 2 == 0 { 0 } else { 255 },
|
||||
],
|
||||
1 if layer == 2 => crate::sprites::FLAT_NORMAL,
|
||||
1 => [128 + layer, 126, 255, 19 + layer],
|
||||
_ => [40 + layer, 50, 60, 255],
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
device.create_texture_with_data(
|
||||
&queue,
|
||||
&wgpu::TextureDescriptor {
|
||||
label: Some("Original fixture companion array"),
|
||||
size: wgpu::Extent3d {
|
||||
width: side,
|
||||
height: side,
|
||||
depth_or_array_layers: count,
|
||||
},
|
||||
mip_level_count: levels,
|
||||
sample_count: 1,
|
||||
dimension: wgpu::TextureDimension::D2,
|
||||
format: wgpu::TextureFormat::Rgba8Unorm,
|
||||
usage: wgpu::TextureUsages::TEXTURE_BINDING
|
||||
| wgpu::TextureUsages::COPY_SRC,
|
||||
view_formats: &[],
|
||||
},
|
||||
wgpu::util::TextureDataOrder::LayerMajor,
|
||||
&pixels,
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
super::super::pack_atlas::PackAtlas::material(
|
||||
&device,
|
||||
&mut encoder,
|
||||
&arrays,
|
||||
split,
|
||||
layers,
|
||||
)
|
||||
.unwrap()
|
||||
})
|
||||
.collect();
|
||||
queue.submit([encoder.finish()]);
|
||||
let pack = horizon_shaders::Pack::open(&root).unwrap();
|
||||
let macros = horizon_shaders::Macros::standard();
|
||||
// Encoded zero alpha is data here and must remain observable in readback.
|
||||
let properties = horizon_shaders::Properties::parse("alphaTest.gbuffers_terrain=off", ¯os);
|
||||
let inputs = horizon_shaders::GameInputs {
|
||||
terrain: Some(horizon_shaders::GbuffersInputs {
|
||||
body: "vec2 p = vec2(float((gl_VertexIndex << 1) & 2), float(gl_VertexIndex & 2)); hz_Vertex=vec4(p*2.0-1.0,0.0,1.0);".into(),
|
||||
..Default::default()
|
||||
}),
|
||||
..Default::default()
|
||||
};
|
||||
let post = horizon_shaders::load_post(&pack, "", &properties, ¯os, &inputs);
|
||||
assert!(post.terrain.is_some(), "{:?}", post.notes);
|
||||
let world = World {
|
||||
sprite_rects: &[],
|
||||
atlas: Some((atlases[2].view.clone(), atlases[2].size())),
|
||||
material_maps: Some([atlases[1].view.clone(), atlases[0].view.clone()]),
|
||||
lightmap: atlases[2].view.clone(),
|
||||
terrain: Some(Geometry {
|
||||
buffers: &[],
|
||||
table: None,
|
||||
depth_write: true,
|
||||
atlas: None,
|
||||
material_maps: true,
|
||||
ids: None,
|
||||
cull: false,
|
||||
}),
|
||||
block_ids: &[],
|
||||
celestial: None,
|
||||
gui_size: [1, 1],
|
||||
clouds: None,
|
||||
weather: false,
|
||||
hand: false,
|
||||
};
|
||||
let mut post = PackPost::new(
|
||||
&device,
|
||||
&queue,
|
||||
&adapter,
|
||||
post,
|
||||
wgpu::TextureFormat::Rgba8Unorm,
|
||||
world,
|
||||
)
|
||||
.expect("the pack runs");
|
||||
let mut pass = post
|
||||
.terrain
|
||||
.take()
|
||||
.unwrap_or_else(|| panic!("terrain pipeline must compile: {:?}", post.notes));
|
||||
// Request the existing copy usage for the fixture's colour readback.
|
||||
post.copied |= 1;
|
||||
// First draw preserves production Geometry -> Pass scope, so a routing regression fails.
|
||||
for case in 0..3 {
|
||||
if case == 1 {
|
||||
pass.material_maps = false;
|
||||
}
|
||||
if case == 2 {
|
||||
pass.material_maps = true;
|
||||
post.material_maps = None;
|
||||
}
|
||||
let maps_expected = case == 0;
|
||||
pass.groups.clear();
|
||||
post.resize(&device, [15, 1]);
|
||||
let read = device.create_buffer(&wgpu::BufferDescriptor {
|
||||
label: None,
|
||||
size: 256,
|
||||
usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::MAP_READ,
|
||||
mapped_at_creation: false,
|
||||
});
|
||||
let mut encoder = device.create_command_encoder(&Default::default());
|
||||
{
|
||||
let _clear = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||
label: Some("Initialize fixture depth"),
|
||||
color_attachments: &[],
|
||||
depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
|
||||
view: &post.targets.as_ref().unwrap().depth,
|
||||
depth_ops: Some(wgpu::Operations {
|
||||
load: wgpu::LoadOp::Clear(1.0),
|
||||
store: wgpu::StoreOp::Store,
|
||||
}),
|
||||
stencil_ops: None,
|
||||
}),
|
||||
..Default::default()
|
||||
});
|
||||
}
|
||||
let group = post.bind(&device, &queue, &mut encoder, &mut pass, [15, 1]);
|
||||
{
|
||||
let mut render = post.begin(&mut encoder, &pass);
|
||||
render.set_pipeline(pass.render());
|
||||
render.set_bind_group(0, &group, &[]);
|
||||
if pass.draw {
|
||||
post.draws.bind(&mut render, "TERRAIN_SOLID");
|
||||
}
|
||||
render.draw(0..3, 0..1);
|
||||
}
|
||||
let output = post.targets.as_ref().unwrap().color[0].as_ref().unwrap()[0].texture();
|
||||
encoder.copy_texture_to_buffer(
|
||||
output.as_image_copy(),
|
||||
wgpu::TexelCopyBufferInfo {
|
||||
buffer: &read,
|
||||
layout: wgpu::TexelCopyBufferLayout {
|
||||
bytes_per_row: Some(256),
|
||||
..Default::default()
|
||||
},
|
||||
},
|
||||
wgpu::Extent3d {
|
||||
width: 15,
|
||||
height: 1,
|
||||
depth_or_array_layers: 1,
|
||||
},
|
||||
);
|
||||
queue.submit([encoder.finish()]);
|
||||
read.slice(..).map_async(wgpu::MapMode::Read, |_| {});
|
||||
device.poll(wgpu::PollType::wait_indefinitely()).unwrap();
|
||||
let data = read.slice(..).get_mapped_range().unwrap();
|
||||
for i in 0..15usize {
|
||||
let layer = (i % 5) as u8;
|
||||
let expected = if i >= 10 {
|
||||
[40 + layer, 50, 60, 255]
|
||||
} else if i >= 5 && (!maps_expected || layer == 2) {
|
||||
crate::sprites::FLAT_NORMAL
|
||||
} else if i >= 5 {
|
||||
[128 + layer, 126, 255, 19 + layer]
|
||||
} else if !maps_expected || layer == 3 {
|
||||
crate::sprites::NO_SPECULAR
|
||||
} else {
|
||||
[17 + layer, 240, 65, 255]
|
||||
};
|
||||
assert_eq!(&data[i * 4..i * 4 + 4], &expected, "case={case}, pixel={i}");
|
||||
}
|
||||
eprintln!("Material oracle case={case}: 15 exact RGBA pixels pass");
|
||||
}
|
||||
// Fault injection: the same production binding must refuse a filtering sampler.
|
||||
// If a regression changed both the binding and sampler, the fractional positive
|
||||
// probes above would instead mix 0.75*240=180 and 0.75*255=191.25, not 240/255.
|
||||
pass.material_maps = true;
|
||||
post.material_maps = Some([atlases[1].view.clone(), atlases[0].view.clone()]);
|
||||
post.nearest_repeat = sampler(&device, wgpu::FilterMode::Linear, wgpu::AddressMode::Repeat);
|
||||
pass.groups.clear();
|
||||
let validation = device.push_error_scope(wgpu::ErrorFilter::Validation);
|
||||
let mut encoder = device.create_command_encoder(&Default::default());
|
||||
let _invalid_group = post.bind(&device, &queue, &mut encoder, &mut pass, [15, 1]);
|
||||
let error = pollster::block_on(validation.pop())
|
||||
.expect("production material binding must reject a filtering sampler");
|
||||
assert!(
|
||||
error.to_string().to_ascii_lowercase().contains("filtering"),
|
||||
"{error}"
|
||||
);
|
||||
eprintln!("Material oracle negative filtering control: rejected by production binding");
|
||||
std::fs::remove_dir_all(root).unwrap();
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,111 @@
|
||||
//! A buffer that isn't cleared, in passes that leave pixels alone or blend: what is under them.
|
||||
//! The expected values are Iris 1.11.7's, measured with probe packs of our own (#9009).
|
||||
use super::*;
|
||||
|
||||
/// colortex6 is written three times a frame, the first write leaving the right half alone:
|
||||
/// there it reads the previous frame's last write, 0.125 (Iris 1.11.7), not the 0.25 written into
|
||||
/// that texture before. colortex8 is written twice a frame the same way: its right half was never
|
||||
/// written and reads 0 (Iris 1.11.7). colortex10 is only blended onto (`ONE ONE`), 0.125 a frame:
|
||||
/// it grows by 0.125 every frame (Iris 1.11.7 adds once per frame).
|
||||
#[test]
|
||||
fn a_buffer_that_is_not_cleared_starts_the_frame_with_its_last_write() {
|
||||
let Some(gpu) = Fixture::new() else { return };
|
||||
let mut zip = zip::ZipWriter::new(Cursor::new(Vec::new()));
|
||||
let mut add = |name: &str, source: &str| {
|
||||
zip.start_file(
|
||||
format!("shaders/{name}"),
|
||||
zip::write::SimpleFileOptions::default(),
|
||||
)
|
||||
.unwrap();
|
||||
zip.write_all(source.as_bytes()).unwrap();
|
||||
};
|
||||
let fill = |v: f32| format!("vec4({v},{v},{v},1)");
|
||||
let programs = [
|
||||
(
|
||||
"composite",
|
||||
format!(
|
||||
"#version 120\nvarying vec2 uv;\n/* RENDERTARGETS:6 */\n\
|
||||
/*\nconst int colortex6Format=RGBA16F;\nconst int colortex7Format=RGBA16F;\n\
|
||||
const int colortex8Format=RGBA16F;\nconst int colortex9Format=RGBA16F;\n\
|
||||
const int colortex10Format=RGBA16F;\nconst bool colortex6Clear=false;\n\
|
||||
const bool colortex8Clear=false;\nconst bool colortex10Clear=false;\n*/\n\
|
||||
void main() {{ if(uv.x>0.5) discard; gl_FragData[0]={}; }}\n",
|
||||
fill(0.5)
|
||||
),
|
||||
),
|
||||
(
|
||||
"composite1",
|
||||
format!(
|
||||
"#version 120\nuniform sampler2D colortex6;\nvarying vec2 uv;\n/* RENDERTARGETS:7,6 */\n\
|
||||
void main() {{ gl_FragData[0]=texture2D(colortex6,uv); gl_FragData[1]={}; }}\n",
|
||||
fill(0.25)
|
||||
),
|
||||
),
|
||||
(
|
||||
"composite2",
|
||||
format!(
|
||||
"#version 120\n/* RENDERTARGETS:6 */\nvoid main() {{ gl_FragData[0]={}; }}\n",
|
||||
fill(0.125)
|
||||
),
|
||||
),
|
||||
(
|
||||
"composite3",
|
||||
format!(
|
||||
"#version 120\nvarying vec2 uv;\n/* RENDERTARGETS:8 */\n\
|
||||
void main() {{ if(uv.x>0.5) discard; gl_FragData[0]={}; }}\n",
|
||||
fill(0.5)
|
||||
),
|
||||
),
|
||||
(
|
||||
"composite4",
|
||||
format!(
|
||||
"#version 120\nuniform sampler2D colortex8;\nvarying vec2 uv;\n/* RENDERTARGETS:9,8 */\n\
|
||||
void main() {{ gl_FragData[0]=texture2D(colortex8,uv); gl_FragData[1]={}; }}\n",
|
||||
fill(0.125)
|
||||
),
|
||||
),
|
||||
(
|
||||
"composite5",
|
||||
"#version 120\n/* RENDERTARGETS:10 */\nvoid main() { gl_FragData[0]=vec4(0.125,0.125,0.125,0); }\n"
|
||||
.to_owned(),
|
||||
),
|
||||
(
|
||||
"final",
|
||||
"#version 120\nuniform sampler2D colortex7;\nuniform sampler2D colortex9;\n\
|
||||
uniform sampler2D colortex10;\nvarying vec2 uv;\n\
|
||||
void main() { gl_FragColor=vec4(texture2D(colortex7,uv).r,texture2D(colortex9,uv).r,texture2D(colortex10,uv).r,1); }\n"
|
||||
.to_owned(),
|
||||
),
|
||||
];
|
||||
for (program, fragment) in &programs {
|
||||
add(&format!("{program}.vsh"), VERTEX);
|
||||
add(&format!("{program}.fsh"), fragment);
|
||||
}
|
||||
add("shaders.properties", "blend.composite5=ONE ONE ONE ONE\n");
|
||||
let pack = horizon_shaders::Pack::from_zip_bytes(
|
||||
"clear-false-history",
|
||||
zip.finish().unwrap().into_inner(),
|
||||
)
|
||||
.unwrap();
|
||||
let mut macros = horizon_shaders::Macros::standard();
|
||||
let (properties, _) = horizon_shaders::read_properties(&pack, &mut macros);
|
||||
let post = horizon_shaders::load_post(&pack, "", &properties, ¯os, &Default::default());
|
||||
let mut post = gpu.build(post);
|
||||
for frame in 0..4u8 {
|
||||
let actual = gpu.render(&mut post, [16, 16]);
|
||||
let sum = 32 * (frame + 1);
|
||||
let wrong: Vec<_> = (actual.iter().enumerate())
|
||||
.filter(|(n, p)| {
|
||||
let expected = match (n % 16 < 8, frame) {
|
||||
(true, _) => [128, 128, sum, 255],
|
||||
(false, 0) => [0, 0, sum, 255],
|
||||
(false, _) => [32, 0, sum, 255],
|
||||
};
|
||||
p.iter().zip(expected).any(|(a, b)| a.abs_diff(b) > 1)
|
||||
})
|
||||
.map(|(n, p)| (n, *p))
|
||||
.take(4)
|
||||
.collect();
|
||||
assert!(wrong.is_empty(), "frame {frame}: {wrong:?}");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
//! A texel offset given by a `const` local reads the texel that far away, as a literal offset
|
||||
//! does (GLSL 4.60, 4.3.3 and 8.9.2, as #8462 quotes them). #8462's probe.
|
||||
use super::destination_tests::Fixture;
|
||||
use super::*;
|
||||
use std::io::{Cursor, Write};
|
||||
|
||||
const VERTEX: &str = "#version 120\nvarying vec2 uv;\nvoid main() { uv=gl_MultiTexCoord0.xy; gl_Position=ftransform(); }\n";
|
||||
|
||||
fn pack() -> Post {
|
||||
let mut zip = zip::ZipWriter::new(Cursor::new(Vec::new()));
|
||||
let mut add = |name: &str, source: &str| {
|
||||
zip.start_file(
|
||||
format!("shaders/{name}"),
|
||||
zip::write::SimpleFileOptions::default(),
|
||||
)
|
||||
.unwrap();
|
||||
zip.write_all(source.as_bytes()).unwrap();
|
||||
};
|
||||
add("composite.vsh", VERTEX);
|
||||
// Each texel of colortex1 holds its own column and row, in eighths.
|
||||
add(
|
||||
"composite.fsh",
|
||||
"#version 120\n/* RENDERTARGETS: 1 */\n\
|
||||
void main() { gl_FragData[0] = vec4(floor(gl_FragCoord.xy) / 8.0, 0.0, 1.0); }\n",
|
||||
);
|
||||
add("final.vsh", VERTEX);
|
||||
// Red and green: what the texel two columns right and one row down holds; blue: this row.
|
||||
add(
|
||||
"final.fsh",
|
||||
"#version 330 compatibility\nuniform sampler2D colortex1;\nin vec2 uv;\n\
|
||||
vec4 f(vec2 p) { const ivec2 offset = ivec2(2, -1); return textureLodOffset(colortex1, p, 0.0, offset); }\n\
|
||||
void main() { gl_FragColor = vec4(f(uv).rg, floor(gl_FragCoord.y) / 8.0, 1.0); }\n",
|
||||
);
|
||||
let pack = horizon_shaders::Pack::from_zip_bytes(
|
||||
"original-const-offset",
|
||||
zip.finish().unwrap().into_inner(),
|
||||
)
|
||||
.unwrap();
|
||||
let mut macros = horizon_shaders::Macros::standard();
|
||||
let (properties, _) = horizon_shaders::read_properties(&pack, &mut macros);
|
||||
let post = horizon_shaders::load_post(&pack, "", &properties, ¯os, &Default::default());
|
||||
assert_eq!(post.programs.len(), 2, "{:?}", post.notes);
|
||||
post
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_const_local_offset_reads_the_offset_texel() {
|
||||
let Some(gpu) = Fixture::new() else { return };
|
||||
let mut post = gpu.build(pack());
|
||||
let pixels = gpu.render(&mut post, [8, 8]);
|
||||
let eighth = |n: u8| (f32::from(n) * 255.0 / 8.0).round() as u8;
|
||||
let mut checked = 0;
|
||||
for (n, p) in pixels.iter().enumerate() {
|
||||
let x = (n % 8) as u8;
|
||||
// The bottom row (GL's row 0) and the two right columns read past the edge.
|
||||
if x >= 6 || p[2] == 0 {
|
||||
continue;
|
||||
}
|
||||
let row = (0..8)
|
||||
.find(|&r| eighth(r).abs_diff(p[2]) <= 1)
|
||||
.expect("row in blue");
|
||||
let want = [eighth(x + 2), eighth(row - 1)];
|
||||
assert!(
|
||||
p[0].abs_diff(want[0]) <= 1 && p[1].abs_diff(want[1]) <= 1,
|
||||
"pixel {n} (column {x}, GL row {row}): {p:?}, expected red and green {want:?}"
|
||||
);
|
||||
checked += 1;
|
||||
}
|
||||
assert_eq!(checked, 6 * 7);
|
||||
}
|
||||
@@ -83,7 +83,8 @@ impl Gpu {
|
||||
post,
|
||||
T::Rgba8Unorm,
|
||||
world,
|
||||
);
|
||||
)
|
||||
.expect("the pack runs");
|
||||
assert!(
|
||||
built.passes.iter().any(|p| p.group == Group::Final),
|
||||
"{:?}",
|
||||
@@ -315,23 +316,26 @@ fn check(sampler: &str, stage: Stage, scene: Scene, expected: [u8; 4]) {
|
||||
let hand = matches!(scene, Scene::Terrain { hand: true, .. });
|
||||
let water = matches!(scene, Scene::Terrain { water: true, .. } | Scene::WaterOnly);
|
||||
let inputs=horizon_shaders::GameInputs {
|
||||
terrain:terrain.then(|| horizon_shaders::GbuffersInputs { declarations:"layout(location=0)in vec3 fixture_position;\n".into(),body:"hz_Vertex=vec4(fixture_position,1.0);hz_Color=vec4(1.0);hz_MultiTexCoord0=vec4(0.0);hz_MultiTexCoord1=vec4(240.0);hz_MultiTexCoord2=vec4(240.0);hz_Normal=vec3(0.0,0.0,1.0);\n".into(),attributes:vec![],after:String::new(),alpha_test:None }),
|
||||
terrain:terrain.then(|| horizon_shaders::GbuffersInputs { declarations:"layout(location=0)in vec3 fixture_position;\n".into(),body:"hz_Vertex=vec4(fixture_position,1.0);hz_Color=vec4(1.0);hz_MultiTexCoord0=vec4(0.0);hz_MultiTexCoord1=vec4(240.0);hz_MultiTexCoord2=vec4(240.0);hz_Normal=vec3(0.0,0.0,1.0);\n".into(),attributes:vec![],after:String::new(),alpha_test:None,item_id_declared:false }),
|
||||
hand:hand.then(crate::gfx::pack_hand::inputs),..Default::default()
|
||||
};
|
||||
let mut post = gpu.load(
|
||||
shaders(sampler, stage, scene),
|
||||
World {
|
||||
atlas: None,
|
||||
material_maps: None,
|
||||
lightmap: color.clone(),
|
||||
terrain: terrain.then_some(Geometry {
|
||||
buffers: &layouts,
|
||||
table: None,
|
||||
depth_write: true,
|
||||
atlas: None,
|
||||
material_maps: false,
|
||||
ids: None,
|
||||
cull: false,
|
||||
}),
|
||||
block_ids: &[],
|
||||
sprite_rects: &[],
|
||||
celestial: None,
|
||||
gui_size: SIZE,
|
||||
clouds: None,
|
||||
@@ -617,6 +621,7 @@ fn fixture_frame(hud: &HudBatch) -> Frame<'_> {
|
||||
celestial: &[],
|
||||
stars: None,
|
||||
hand: &[],
|
||||
hand_items: &[],
|
||||
hand_fov_degrees: 70.0,
|
||||
screen: &[],
|
||||
pack: Default::default(),
|
||||
@@ -635,3 +640,144 @@ fn fixture_frame(hud: &HudBatch) -> Frame<'_> {
|
||||
post_effects: crate::post_chain::Request::none(),
|
||||
}
|
||||
}
|
||||
|
||||
/// shadowtex0 and shadowtex1 read through a plain sampler a quarter texel past a texel's centre,
|
||||
/// over a shadow map whose depth rises a sixteenth a texel: red and green are how far each
|
||||
/// moved toward the next texel, times four (0 nearest, 255 linear). `nearest` is a line for
|
||||
/// both stage files.
|
||||
fn shadow_depth_filtering(nearest: &str) -> Option<Vec<[u8; 4]>> {
|
||||
let gpu = Gpu::new()?;
|
||||
if !gpu
|
||||
.device
|
||||
.features()
|
||||
.contains(wgpu::Features::FLOAT32_FILTERABLE)
|
||||
{
|
||||
eprintln!("DEPTH_FIXTURE_NO_FLOAT32_FILTERABLE");
|
||||
return None;
|
||||
}
|
||||
let color = gpu.texture(T::Rgba8Unorm);
|
||||
let depth = gpu.texture(T::Depth32Float);
|
||||
gpu.clear(&color, &depth, 0.0);
|
||||
const ATTRS: [wgpu::VertexAttribute; 1] = wgpu::vertex_attr_array![0=>Float32x3];
|
||||
let layouts = [Some(wgpu::VertexBufferLayout {
|
||||
array_stride: 12,
|
||||
step_mode: wgpu::VertexStepMode::Vertex,
|
||||
attributes: &ATTRS,
|
||||
})];
|
||||
let inputs = horizon_shaders::GameInputs {
|
||||
terrain: Some(horizon_shaders::GbuffersInputs {
|
||||
declarations: "layout(location=0)in vec3 fixture_position;\n".into(),
|
||||
body: "hz_Vertex=vec4(fixture_position,1.0);hz_Color=vec4(1.0);\
|
||||
hz_MultiTexCoord0=vec4(0.0);hz_MultiTexCoord1=vec4(240.0);\
|
||||
hz_MultiTexCoord2=vec4(240.0);hz_Normal=vec3(0.0,0.0,1.0);\n"
|
||||
.into(),
|
||||
attributes: vec![],
|
||||
after: String::new(),
|
||||
alpha_test: None,
|
||||
item_id_declared: false,
|
||||
}),
|
||||
..Default::default()
|
||||
};
|
||||
let settings = format!("const int shadowMapResolution = 16;\n{nearest}\n");
|
||||
let files = vec![
|
||||
("final.vsh".to_string(), VERTEX.to_string()),
|
||||
(
|
||||
"final.fsh".into(),
|
||||
format!(
|
||||
"#version 330 compatibility\n{settings}\
|
||||
uniform sampler2D shadowtex0;\nuniform sampler2D shadowtex1;\n\
|
||||
float moved(sampler2D s, ivec2 t) {{\n\
|
||||
float a = texelFetch(s, t, 0).r;\n\
|
||||
return (texture(s, (vec2(t) + vec2(0.75, 0.5)) / 16.0).r - a) * 16.0;\n\
|
||||
}}\n\
|
||||
void main() {{\n\
|
||||
ivec2 t = ivec2(int(gl_FragCoord.x) % 15, 8);\n\
|
||||
gl_FragColor = vec4(moved(shadowtex0, t) * 4.0, moved(shadowtex1, t) * 4.0, 0.0, 1.0);\n\
|
||||
}}\n"
|
||||
),
|
||||
),
|
||||
// The shadow map's depth runs from 0 at its left edge to 1 at its right.
|
||||
(
|
||||
"shadow.vsh".into(),
|
||||
"#version 120\nvoid main(){gl_Position=vec4(gl_Vertex.xy,gl_Vertex.x,1.0);}".into(),
|
||||
),
|
||||
(
|
||||
"shadow.fsh".into(),
|
||||
format!("#version 120\n{settings}void main(){{gl_FragData[0]=vec4(1.0);}}"),
|
||||
),
|
||||
];
|
||||
let mut post = gpu.load(
|
||||
files,
|
||||
World {
|
||||
sprite_rects: &[],
|
||||
atlas: None,
|
||||
material_maps: None,
|
||||
lightmap: color.clone(),
|
||||
terrain: Some(Geometry {
|
||||
buffers: &layouts,
|
||||
table: None,
|
||||
depth_write: true,
|
||||
atlas: None,
|
||||
ids: None,
|
||||
cull: false,
|
||||
material_maps: false,
|
||||
}),
|
||||
block_ids: &[],
|
||||
celestial: None,
|
||||
gui_size: SIZE,
|
||||
clouds: None,
|
||||
weather: false,
|
||||
hand: false,
|
||||
},
|
||||
inputs,
|
||||
);
|
||||
assert!(post.has_shadow(), "{:?}", post.notes);
|
||||
let positions: [[f32; 3]; 6] = [
|
||||
[-1., -1., 0.],
|
||||
[1., -1., 0.],
|
||||
[1., 1., 0.],
|
||||
[-1., -1., 0.],
|
||||
[1., 1., 0.],
|
||||
[-1., 1., 0.],
|
||||
];
|
||||
let vertices = gpu
|
||||
.device
|
||||
.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||
label: Some("Original shadow depth ramp"),
|
||||
contents: bytemuck::cast_slice(&positions),
|
||||
usage: wgpu::BufferUsages::VERTEX,
|
||||
});
|
||||
let hud = HudBatch::new(SIZE);
|
||||
let frame = fixture_frame(&hud);
|
||||
Some(
|
||||
gpu.render(&mut post, &color, &depth, &frame, &mut |rp, list, _, _| {
|
||||
if list == TerrainList::ShadowSolid {
|
||||
rp.set_vertex_buffer(0, vertices.slice(..));
|
||||
rp.draw(0..6, 0..1);
|
||||
}
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn shadow_depth_is_read_linearly_through_a_plain_sampler() {
|
||||
// Iris 1.11.7 filters both (probe packs of our own; the PR has the readings).
|
||||
if let Some(pixels) = shadow_depth_filtering("") {
|
||||
all_pixels(&pixels, [255, 255, 0, 255], "shadowtex linear");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn shadowtex_nearest_settings_read_the_nearest_texel() {
|
||||
for (line, expected) in [
|
||||
("const bool shadowtex0Nearest = true;", [0, 255, 0, 255]),
|
||||
("const bool shadowtexNearest = true;", [0, 255, 0, 255]),
|
||||
("const bool shadow0MinMagNearest = true;", [0, 255, 0, 255]),
|
||||
("const bool shadowtex1Nearest = true;", [255, 0, 0, 255]),
|
||||
("const bool shadow1MinMagNearest = true;", [255, 0, 0, 255]),
|
||||
] {
|
||||
if let Some(pixels) = shadow_depth_filtering(line) {
|
||||
all_pixels(&pixels, expected, line);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -199,8 +199,19 @@ impl Fixture {
|
||||
}
|
||||
|
||||
pub(super) fn build(&self, post: Post) -> PackPost {
|
||||
let post = self.try_build(post).expect("the pack runs");
|
||||
assert!(
|
||||
post.notes.iter().all(|n| n.starts_with("shadow map ")),
|
||||
"{:?}",
|
||||
post.notes
|
||||
);
|
||||
post
|
||||
}
|
||||
|
||||
/// [`Self::build`] for a pack that may be refused.
|
||||
pub(super) fn try_build(&self, post: Post) -> Result<PackPost, Refused> {
|
||||
let lightmap = self.texture([1, 1], T::Rgba8Unorm);
|
||||
let post = PackPost::new(
|
||||
PackPost::new(
|
||||
&self.device,
|
||||
&self.queue,
|
||||
&self.adapter,
|
||||
@@ -208,22 +219,18 @@ impl Fixture {
|
||||
T::Rgba8Unorm,
|
||||
World {
|
||||
atlas: None,
|
||||
material_maps: None,
|
||||
lightmap,
|
||||
terrain: None,
|
||||
block_ids: &[],
|
||||
sprite_rects: &[],
|
||||
celestial: None,
|
||||
gui_size: [16, 16],
|
||||
clouds: None,
|
||||
weather: false,
|
||||
hand: false,
|
||||
},
|
||||
);
|
||||
assert!(
|
||||
post.notes.iter().all(|n| n.starts_with("shadow map ")),
|
||||
"{:?}",
|
||||
post.notes
|
||||
);
|
||||
post
|
||||
)
|
||||
}
|
||||
|
||||
pub(super) fn render(&self, post: &mut PackPost, size: [u32; 2]) -> Vec<[u8; 4]> {
|
||||
@@ -346,8 +353,8 @@ fn frame_clear_and_retained_history_apply_before_partial_post_writes() {
|
||||
let Some(gpu) = Fixture::new() else { return };
|
||||
for clear in [true, false] {
|
||||
let mut post = gpu.build(pack(Coverage::Full, false, false, Some(clear), false));
|
||||
// Every frame changes which physical image is main. The other image is fully
|
||||
// seeded red before the partial write, independent of its initial clearing.
|
||||
// The other image is fully seeded red before the partial write, independent of its
|
||||
// initial clearing.
|
||||
for frame in 0..3 {
|
||||
let actual = gpu.render(&mut post, [16, 16]);
|
||||
assert!(
|
||||
@@ -433,6 +440,7 @@ fn fixture_frame(hud: &HudBatch) -> Frame<'_> {
|
||||
celestial: &[],
|
||||
stars: None,
|
||||
hand: &[],
|
||||
hand_items: &[],
|
||||
hand_fov_degrees: 70.0,
|
||||
screen: &[],
|
||||
pack: Default::default(),
|
||||
@@ -521,3 +529,6 @@ fn a_cleared_buffer_starts_every_frame_cleared_on_both_textures() {
|
||||
assert!(wrong.is_empty(), "frame {frame}: {wrong:?}");
|
||||
}
|
||||
}
|
||||
|
||||
#[path = "clear_false_tests.rs"]
|
||||
mod clear_false_tests;
|
||||
@@ -0,0 +1,73 @@
|
||||
//! `flip.<program>.<buffer> = true` on a buffer the program writes (#9010). The expected values
|
||||
//! are Iris 1.11.7's, measured with probe packs of our own.
|
||||
use super::destination_tests::Fixture;
|
||||
use std::io::{Cursor, Write};
|
||||
|
||||
const VERTEX: &str = "#version 120\nvarying vec2 uv;\nvoid main() { uv=gl_MultiTexCoord0.xy; gl_Position=ftransform(); }\n";
|
||||
|
||||
/// `composite` writes 0.25 to colortex2 and colortex4 and forces both to flip: the forced flip
|
||||
/// cancels the write's own, so `composite1` samples colortex2's cleared side (Iris 1.11.7: 0),
|
||||
/// and `composite2`, blended `ONE ONE`, adds 0.5 onto colortex4's 0.25 (Iris 1.11.7: 0.749).
|
||||
#[test]
|
||||
fn a_forced_flip_of_a_written_buffer_leaves_it_unflipped() {
|
||||
let Some(gpu) = Fixture::new() else { return };
|
||||
let mut zip = zip::ZipWriter::new(Cursor::new(Vec::new()));
|
||||
let mut add = |name: &str, source: &str| {
|
||||
zip.start_file(
|
||||
format!("shaders/{name}"),
|
||||
zip::write::SimpleFileOptions::default(),
|
||||
)
|
||||
.unwrap();
|
||||
zip.write_all(source.as_bytes()).unwrap();
|
||||
};
|
||||
for (program, fragment) in [
|
||||
(
|
||||
"composite",
|
||||
"#version 120\n/* RENDERTARGETS:2,4 */\n\
|
||||
void main() { gl_FragData[0]=vec4(0.25,0.25,0.25,1); gl_FragData[1]=vec4(0.25,0.25,0.25,1); }\n",
|
||||
),
|
||||
(
|
||||
"composite1",
|
||||
"#version 120\nuniform sampler2D colortex2;\nvarying vec2 uv;\n/* RENDERTARGETS:3 */\n\
|
||||
void main() { gl_FragData[0]=texture2D(colortex2,uv); }\n",
|
||||
),
|
||||
(
|
||||
"composite2",
|
||||
"#version 120\n/* RENDERTARGETS:4 */\nvoid main() { gl_FragData[0]=vec4(0.5,0.5,0.5,0); }\n",
|
||||
),
|
||||
(
|
||||
"final",
|
||||
"#version 120\nuniform sampler2D colortex3;\nuniform sampler2D colortex4;\nvarying vec2 uv;\n\
|
||||
void main() { gl_FragColor=vec4(texture2D(colortex4,uv).r,texture2D(colortex3,uv).r,0,1); }\n",
|
||||
),
|
||||
] {
|
||||
add(&format!("{program}.vsh"), VERTEX);
|
||||
add(&format!("{program}.fsh"), fragment);
|
||||
}
|
||||
add(
|
||||
"shaders.properties",
|
||||
"flip.composite.colortex2=true\nflip.composite.colortex4=true\nblend.composite2=ONE ONE ONE ONE\n",
|
||||
);
|
||||
let pack = horizon_shaders::Pack::from_zip_bytes(
|
||||
"forced-flip-of-a-written-buffer",
|
||||
zip.finish().unwrap().into_inner(),
|
||||
)
|
||||
.unwrap();
|
||||
let mut macros = horizon_shaders::Macros::standard();
|
||||
let (properties, _) = horizon_shaders::read_properties(&pack, &mut macros);
|
||||
let post = horizon_shaders::load_post(&pack, "", &properties, ¯os, &Default::default());
|
||||
let mut post = gpu.build(post);
|
||||
for frame in 0..2 {
|
||||
let actual = gpu.render(&mut post, [16, 16]);
|
||||
let wrong: Vec<_> = (actual.iter().enumerate())
|
||||
.filter(|(_, p)| {
|
||||
p.iter()
|
||||
.zip([191, 0, 0, 255])
|
||||
.any(|(a, b)| a.abs_diff(b) > 1)
|
||||
})
|
||||
.map(|(n, p)| (n, *p))
|
||||
.take(4)
|
||||
.collect();
|
||||
assert!(wrong.is_empty(), "frame {frame}: {wrong:?}");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
//! A pack may give colortex0 an integer format (OptiFine's `shaders.txt`, "Texture Formats",
|
||||
//! lists `RGBA32UI`, as #8459 quotes it): the pack still loads, and reads back what it wrote
|
||||
//! there. #8459's probe; #8459 reports Iris 1.11.7 drawing (0, 200, 0) at every point
|
||||
//! sampled from it. Without a `final` that draws it, the pack is refused (#9165).
|
||||
use super::destination_tests::Fixture;
|
||||
use super::*;
|
||||
use std::io::{Cursor, Write};
|
||||
|
||||
const VERTEX: &str = "#version 120\nvarying vec2 uv;\nvoid main() { uv=gl_MultiTexCoord0.xy; gl_Position=ftransform(); }\n";
|
||||
|
||||
/// A `final` that shows the integer colortex0.
|
||||
const FINAL: &str = "#version 330 compatibility\nuniform usampler2D colortex0;\n\
|
||||
void main() { gl_FragColor = vec4(texelFetch(colortex0, ivec2(gl_FragCoord.xy), 0)) / 255.0; }\n";
|
||||
|
||||
/// A `final` that doesn't compile (it calls a function nobody declares), so it is skipped.
|
||||
const BROKEN_FINAL: &str =
|
||||
"#version 330 compatibility\nvoid main() { gl_FragColor = undeclared_function(); }\n";
|
||||
|
||||
/// `depth`: the composite reads depthtex0, so the blit copies the world's depth; `last`: the
|
||||
/// pack's `final`, if it has one.
|
||||
fn pack(depth: bool, last: Option<&str>) -> Post {
|
||||
let mut zip = zip::ZipWriter::new(Cursor::new(Vec::new()));
|
||||
let mut add = |name: &str, source: &str| {
|
||||
zip.start_file(
|
||||
format!("shaders/{name}"),
|
||||
zip::write::SimpleFileOptions::default(),
|
||||
)
|
||||
.unwrap();
|
||||
zip.write_all(source.as_bytes()).unwrap();
|
||||
};
|
||||
add("composite.vsh", VERTEX);
|
||||
// With depthtex0: green where it holds the empty world's far plane (1), red elsewhere.
|
||||
let value = if depth {
|
||||
"texelFetch(depthtex0, ivec2(gl_FragCoord.xy), 0).r == 1.0 ? uvec4(0u, 200u, 0u, 255u) : uvec4(200u, 0u, 0u, 255u)"
|
||||
} else {
|
||||
"uvec4(0u, 200u, 0u, 255u)"
|
||||
};
|
||||
add(
|
||||
"composite.fsh",
|
||||
&format!(
|
||||
"#version 330 compatibility\n/* RENDERTARGETS: 0 */\n/*\nconst int colortex0Format = RGBA32UI;\n*/\n\
|
||||
uniform sampler2D depthtex0;\nlayout(location = 0) out uvec4 o;\nvoid main() {{ o = {value}; }}\n"
|
||||
),
|
||||
);
|
||||
if let Some(source) = last {
|
||||
add("final.vsh", VERTEX);
|
||||
add("final.fsh", source);
|
||||
}
|
||||
let pack = horizon_shaders::Pack::from_zip_bytes(
|
||||
"original-integer-colortex0",
|
||||
zip.finish().unwrap().into_inner(),
|
||||
)
|
||||
.unwrap();
|
||||
let mut macros = horizon_shaders::Macros::standard();
|
||||
let (properties, _) = horizon_shaders::read_properties(&pack, &mut macros);
|
||||
horizon_shaders::load_post(&pack, "", &properties, ¯os, &Default::default())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn an_integer_colortex0_keeps_what_the_pack_wrote() {
|
||||
let Some(gpu) = Fixture::new() else { return };
|
||||
for depth in [false, true] {
|
||||
let mut post = gpu.build(pack(depth, Some(FINAL)));
|
||||
// Twice: the second frame's world blit runs over a colortex0 the first frame wrote.
|
||||
for frame in 0..2 {
|
||||
let pixels = gpu.render(&mut post, [8, 8]);
|
||||
let wrong: Vec<_> = pixels.iter().filter(|p| **p != [0, 200, 0, 255]).collect();
|
||||
assert!(wrong.is_empty(), "depth {depth}, frame {frame}: {wrong:?}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Without a `final` left to draw it (none, or one that is skipped), an integer colortex0 has
|
||||
/// no colours the screen can show: the pack is refused, so the game turns it off and draws
|
||||
/// without it instead of a black screen (#9165). The refusal keeps why `final` was skipped.
|
||||
#[test]
|
||||
fn an_integer_colortex0_without_a_working_final_is_refused() {
|
||||
let Some(gpu) = Fixture::new() else { return };
|
||||
for last in [None, Some(BROKEN_FINAL)] {
|
||||
let Err(refused) = gpu.try_build(pack(false, last)) else {
|
||||
panic!("{last:?}: a pack that can't show colortex0 runs");
|
||||
};
|
||||
assert_eq!(
|
||||
refused.notes.iter().any(|n| n.starts_with("final")),
|
||||
last.is_some(),
|
||||
"{refused:?}"
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,205 @@
|
||||
//! The small packed colortex formats `RGB5_A1`, `RGB565` and `R3_G3_B2`, read back as in Iris
|
||||
//! 1.11.7. wgpu has no such formats, so these buffers are 8-bit (`texture_format`); what a pass
|
||||
//! writes into one and its clear colour go through [`quantise`] first.
|
||||
//!
|
||||
//! Probe pack p8106c of our own wrote 600 values to each format and read them back with
|
||||
//! `texelFetch` in Iris 1.11.7 (NVIDIA 615.78.08). Our probe's Iris values fit this, with no
|
||||
//! exception: each channel becomes the byte an `RGBA8` buffer stores for it, keeps that byte's
|
||||
//! top bits (5, 5, 5 and 1 for `RGB5_A1`; 5, 6 and 5 for `RGB565` and also for `R3_G3_B2`), and
|
||||
//! reads back those bits repeated to fill 8 (`0.3337` → byte 85 → 10 of 31 → 82 / 255). This is
|
||||
//! a fit to one driver's values, not a rule Iris states. `RGBA4` and `RGBA2` read back the `RGBA8`
|
||||
//! bytes in the same probe, as Horizon's 8-bit buffers already do.
|
||||
|
||||
use horizon_shaders::{Format, Kind};
|
||||
use naga::{BinaryOperator, Expression, Literal, MathFunction, Statement, VectorSize};
|
||||
|
||||
/// The bits each channel keeps in a buffer of format `f`, for the formats that keep fewer than
|
||||
/// 8; a three-channel format's alpha keeps 8 (it reads 1 anyway).
|
||||
pub(super) fn bits(f: Format) -> Option<[u8; 4]> {
|
||||
match (f.kind, f.channels, f.bits) {
|
||||
(Kind::Unorm, 4, 5) => Some([5, 5, 5, 1]),
|
||||
// `RGB565`, and `R3_G3_B2` (3 × 3 bits in `config.rs`), which our probe's Iris values
|
||||
// put in 5, 6 and 5 bits too.
|
||||
(Kind::Unorm, 3, 6 | 3) => Some([5, 6, 5, 8]),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// The value a buffer keeping `bits` per channel reads back after `v` is written or cleared.
|
||||
pub(super) fn quantise(v: [f32; 4], bits: [u8; 4]) -> [f32; 4] {
|
||||
std::array::from_fn(|i| {
|
||||
let byte = (v[i].clamp(0.0, 1.0) * 255.0 + 0.5).floor() as u32;
|
||||
let n = u32::from(bits[i]);
|
||||
let kept = byte >> (8 - n);
|
||||
// The kept bits, repeated until there are 8.
|
||||
let mut wide = 0;
|
||||
let mut have = 0;
|
||||
while have < 8 {
|
||||
wide = wide << n | kept;
|
||||
have += n;
|
||||
}
|
||||
(wide >> (have - 8)) as f32 / 255.0
|
||||
})
|
||||
}
|
||||
|
||||
/// The factors of the shader's [`quantise`] for a channel keeping `n` bits: the kept value is
|
||||
/// `floor(byte / step)`, and it reads back `kept × step + floor(kept × repeat)`.
|
||||
fn factors(n: u8) -> (f32, f32) {
|
||||
let step = f32::from(1u16 << (8 - n));
|
||||
// `kept × repeat` is the kept bits shifted down to fill what `kept × step` leaves: one bit
|
||||
// fills the other 7 (× 127); 5 or 6 bits fill 3 or 2 with their top bits.
|
||||
let repeat = match n {
|
||||
1 => 127.0,
|
||||
_ => 2f32.powi(8 - 2 * i32::from(n)),
|
||||
};
|
||||
(step, repeat)
|
||||
}
|
||||
|
||||
/// Makes the fragment entry point of `module` write each output location of `outputs` as
|
||||
/// [`quantise`] gives it for its bits. The translator's entry point ends in one `return` of its
|
||||
/// outputs; a module without one is left as it is.
|
||||
pub(super) fn quantise_outputs(module: &mut naga::Module, outputs: &[(u32, [u8; 4])]) {
|
||||
let Some(ep) =
|
||||
(module.entry_points.iter_mut()).find(|e| e.stage == naga::ShaderStage::Fragment)
|
||||
else {
|
||||
return;
|
||||
};
|
||||
let Some(result) = &ep.function.result else {
|
||||
return;
|
||||
};
|
||||
let naga::TypeInner::Struct { members, .. } = &module.types[result.ty].inner else {
|
||||
return;
|
||||
};
|
||||
let vec4 = |ty: naga::Handle<naga::Type>| {
|
||||
matches!(
|
||||
module.types[ty].inner,
|
||||
naga::TypeInner::Vector {
|
||||
size: VectorSize::Quad,
|
||||
scalar: naga::Scalar::F32
|
||||
}
|
||||
)
|
||||
};
|
||||
// (member, bits, the member's type) of each output to change.
|
||||
let changed: Vec<(usize, [u8; 4], naga::Handle<naga::Type>)> = (members.iter().enumerate())
|
||||
.filter_map(|(i, m)| {
|
||||
let Some(naga::Binding::Location { location, .. }) = m.binding else {
|
||||
return None;
|
||||
};
|
||||
let bits = outputs.iter().find(|o| o.0 == location)?.1;
|
||||
vec4(m.ty).then_some((i, bits, m.ty))
|
||||
})
|
||||
.collect();
|
||||
if changed.is_empty() {
|
||||
return;
|
||||
}
|
||||
let struct_ty = result.ty;
|
||||
let f = &mut ep.function;
|
||||
let body = std::mem::take(&mut f.body);
|
||||
let mut out = naga::Block::with_capacity(body.len() + 1);
|
||||
for (statement, span) in body.span_into_iter() {
|
||||
let Statement::Return { value: Some(value) } = statement else {
|
||||
out.push(statement, span);
|
||||
continue;
|
||||
};
|
||||
let Expression::Compose { components, .. } = &f.expressions[value] else {
|
||||
out.push(statement, span);
|
||||
continue;
|
||||
};
|
||||
let mut components = components.clone();
|
||||
let e = &mut f.expressions;
|
||||
let lit = |e: &mut naga::Arena<Expression>, v: f32| {
|
||||
e.append(Expression::Literal(Literal::F32(v)), span)
|
||||
};
|
||||
// Literals need no emitting: they come before the range that is emitted.
|
||||
let scalars: Vec<_> = (changed.iter())
|
||||
.map(|&(_, bits, _)| {
|
||||
let per = bits.map(factors);
|
||||
(
|
||||
per.map(|(step, _)| lit(e, step)),
|
||||
per.map(|(step, _)| lit(e, 1.0 / step)),
|
||||
per.map(|(_, repeat)| lit(e, repeat)),
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
let (zero, one, max, half) = (lit(e, 0.0), lit(e, 1.0), lit(e, 255.0), lit(e, 0.5));
|
||||
let mut add = |x: Expression| e.append(x, span);
|
||||
let splat = |add: &mut dyn FnMut(Expression) -> _, value| {
|
||||
add(Expression::Splat {
|
||||
size: VectorSize::Quad,
|
||||
value,
|
||||
})
|
||||
};
|
||||
let (zero, one, max, half) = (
|
||||
splat(&mut add, zero),
|
||||
splat(&mut add, one),
|
||||
splat(&mut add, max),
|
||||
splat(&mut add, half),
|
||||
);
|
||||
let binary = |add: &mut dyn FnMut(Expression) -> _, op, left, right| {
|
||||
add(Expression::Binary { op, left, right })
|
||||
};
|
||||
let math = |add: &mut dyn FnMut(Expression) -> _, fun, arg, arg1, arg2| {
|
||||
add(Expression::Math {
|
||||
fun,
|
||||
arg,
|
||||
arg1,
|
||||
arg2,
|
||||
arg3: None,
|
||||
})
|
||||
};
|
||||
for (&(member, _, ty), (steps, inverse, repeats)) in changed.iter().zip(scalars) {
|
||||
let mut vector = |components: [_; 4]| {
|
||||
add(Expression::Compose {
|
||||
ty,
|
||||
components: components.to_vec(),
|
||||
})
|
||||
};
|
||||
let (step, inverse, repeat) = (vector(steps), vector(inverse), vector(repeats));
|
||||
let x = components[member];
|
||||
let clamped = math(&mut add, MathFunction::Clamp, x, Some(zero), Some(one));
|
||||
let scaled = binary(&mut add, BinaryOperator::Multiply, clamped, max);
|
||||
let rounded = binary(&mut add, BinaryOperator::Add, scaled, half);
|
||||
let byte = math(&mut add, MathFunction::Floor, rounded, None, None);
|
||||
let shifted = binary(&mut add, BinaryOperator::Multiply, byte, inverse);
|
||||
let kept = math(&mut add, MathFunction::Floor, shifted, None, None);
|
||||
let high = binary(&mut add, BinaryOperator::Multiply, kept, step);
|
||||
let low = binary(&mut add, BinaryOperator::Multiply, kept, repeat);
|
||||
let low = math(&mut add, MathFunction::Floor, low, None, None);
|
||||
let wide = binary(&mut add, BinaryOperator::Add, high, low);
|
||||
components[member] = binary(&mut add, BinaryOperator::Divide, wide, max);
|
||||
}
|
||||
let value = add(Expression::Compose {
|
||||
ty: struct_ty,
|
||||
components,
|
||||
});
|
||||
// Everything from the first splat on is new and not a literal.
|
||||
let range = naga::Range::new_from_bounds(zero, value);
|
||||
out.push(Statement::Emit(range), span);
|
||||
out.push(Statement::Return { value: Some(value) }, span);
|
||||
}
|
||||
f.body = out;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn clear_colours_keep_the_same_bits() {
|
||||
// The CPU side, for clear colours. Iris 1.11.7 read p8106d's clear colour back as below in
|
||||
// RGB5_A1 and RGB565, and p8106c's 0.3337 as 82/255 in the 5-bit channels and 85/255 in
|
||||
// the 6-bit one.
|
||||
let to_255 = |v: [f32; 4]| v.map(|c| (c * 255.0 * 1000.0).round() / 1000.0);
|
||||
let rgb5_a1 = bits(Format::parse("RGB5_A1").unwrap()).unwrap();
|
||||
let rgb565 = bits(Format::parse("RGB565").unwrap()).unwrap();
|
||||
let r3_g3_b2 = bits(Format::parse("R3_G3_B2").unwrap()).unwrap();
|
||||
let clear = [0.3337, 0.1, 0.6, 0.3];
|
||||
assert_eq!(to_255(quantise(clear, rgb5_a1)), [82.0, 24.0, 156.0, 0.0]);
|
||||
assert_eq!(to_255(quantise(clear, rgb565))[..3], [82.0, 24.0, 156.0]);
|
||||
assert_eq!(
|
||||
to_255(quantise([0.3337; 4], r3_g3_b2))[..3],
|
||||
[82.0, 85.0, 82.0]
|
||||
);
|
||||
assert!(bits(Format::parse("RGBA4").unwrap()).is_none());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
//! `RGB5_A1`, `RGB565` and `R3_G3_B2` buffers read back as in Iris 1.11.7. Expected values are
|
||||
//! those probe packs p8106c (written values) and p8106d (clear colours) read back in Iris (the PR
|
||||
//! has them); the programs here are the probes', cut down. Written values are ones whose byte
|
||||
//! (× 255) is not near a half: GPUs may round those either way.
|
||||
use super::destination_tests::Fixture;
|
||||
use super::*;
|
||||
use std::io::{Cursor, Write};
|
||||
|
||||
const VERTEX: &str = "#version 120\nvarying vec2 uv;\nvoid main() { uv=gl_MultiTexCoord0.xy; gl_Position=ftransform(); }\n";
|
||||
|
||||
fn pack() -> Post {
|
||||
let mut zip = zip::ZipWriter::new(Cursor::new(Vec::new()));
|
||||
let mut add = |name: &str, source: &str| {
|
||||
zip.start_file(
|
||||
format!("shaders/{name}"),
|
||||
zip::write::SimpleFileOptions::default(),
|
||||
)
|
||||
.unwrap();
|
||||
zip.write_all(source.as_bytes()).unwrap();
|
||||
};
|
||||
add("composite.vsh", VERTEX);
|
||||
add(
|
||||
"composite.fsh",
|
||||
"#version 120\n/* RENDERTARGETS: 1,2,3 */\n\
|
||||
/*\nconst int colortex1Format = RGB5_A1;\nconst int colortex2Format = RGB565;\n\
|
||||
const int colortex3Format = R3_G3_B2;\nconst int colortex4Format = RGB5_A1;\n\
|
||||
const int colortex5Format = RGB565;\n*/\n\
|
||||
const vec4 colortex4ClearColor = vec4(0.3337, 0.1, 0.6, 0.3);\n\
|
||||
const vec4 colortex5ClearColor = vec4(0.3337, 0.1, 0.6, 0.3);\n\
|
||||
void main() {\n\
|
||||
gl_FragData[0] = vec4(175.0, 176.0, 766.5, 256.0) / 511.0;\n\
|
||||
gl_FragData[1] = vec4(400.0, 175.0, 44.0, 0.0) / 511.0;\n\
|
||||
gl_FragData[2] = vec4(-255.5, 176.0, 300.0, 0.0) / 511.0;\n}\n",
|
||||
);
|
||||
add("final.vsh", VERTEX);
|
||||
// Pixel column x shows component x % 4 of buffer 1 + x / 4, as the bytes of its bits.
|
||||
add(
|
||||
"final.fsh",
|
||||
"#version 330 compatibility\nuniform sampler2D colortex1;\nuniform sampler2D colortex2;\n\
|
||||
uniform sampler2D colortex3;\nuniform sampler2D colortex4;\nuniform sampler2D colortex5;\n\
|
||||
void main() {\n ivec2 p = ivec2(gl_FragCoord.xy);\n vec4 c = vec4(0.0);\n\
|
||||
switch (p.x / 4) {\n\
|
||||
case 0: c = texelFetch(colortex1, p, 0); break;\n\
|
||||
case 1: c = texelFetch(colortex2, p, 0); break;\n\
|
||||
case 2: c = texelFetch(colortex3, p, 0); break;\n\
|
||||
case 3: c = texelFetch(colortex4, p, 0); break;\n\
|
||||
case 4: c = texelFetch(colortex5, p, 0); break;\n\
|
||||
}\n uint u = floatBitsToUint(c[p.x % 4]);\n\
|
||||
gl_FragColor = vec4(uvec4(u >> 24u, u >> 16u, u >> 8u, u) & 255u) / 255.0;\n}\n",
|
||||
);
|
||||
let pack = horizon_shaders::Pack::from_zip_bytes(
|
||||
"original-packed",
|
||||
zip.finish().unwrap().into_inner(),
|
||||
)
|
||||
.unwrap();
|
||||
let mut macros = horizon_shaders::Macros::standard();
|
||||
let (properties, _) = horizon_shaders::read_properties(&pack, &mut macros);
|
||||
let post = horizon_shaders::load_post(&pack, "", &properties, ¯os, &Default::default());
|
||||
assert_eq!(post.programs.len(), 2, "{:?}", post.notes);
|
||||
post
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn small_packed_buffers_keep_their_bits() {
|
||||
let Some(gpu) = Fixture::new() else { return };
|
||||
let mut post = gpu.build(pack());
|
||||
// Twice: the second frame writes the buffers' other sides.
|
||||
for frame in 0..2 {
|
||||
let pixels = gpu.render(&mut post, [20, 1]);
|
||||
let read: Vec<f32> = pixels
|
||||
.iter()
|
||||
.map(|p| f32::from_bits(u32::from_be_bytes(*p)))
|
||||
.collect();
|
||||
// Iris 1.11.7, in 255ths: RGB5_A1 written (175, 176, 766.5, 256) / 511; RGB565 written
|
||||
// (400, 175, 44, 0) / 511; R3_G3_B2 written (-255.5, 176, 300, 0) / 511; RGB5_A1 and
|
||||
// RGB565 cleared to (0.3337, 0.1, 0.6, 0.3). Three-channel formats read alpha 1.
|
||||
let expected: [f32; 20] = [
|
||||
82.0, 90.0, 255.0, 255.0, //
|
||||
206.0, 85.0, 16.0, 255.0, //
|
||||
0.0, 89.0, 148.0, 255.0, //
|
||||
82.0, 24.0, 156.0, 0.0, //
|
||||
82.0, 24.0, 156.0, 255.0,
|
||||
];
|
||||
for (n, (got, want)) in read.iter().zip(expected).enumerate() {
|
||||
assert!(
|
||||
(got - want / 255.0).abs() <= 1e-6,
|
||||
"frame {frame}, buffer {} component {}: {}/255, expected {want}/255; all {:?}",
|
||||
1 + n / 4,
|
||||
n % 4,
|
||||
got * 255.0,
|
||||
read.iter().map(|v| v * 255.0).collect::<Vec<_>>()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
//! `min3`, `max3` and `mid3` of GL_AMD_shader_trinary_minmax: the per-component minimum, maximum
|
||||
//! and median of three values, for float, int and uint vectors (the extension's additions to
|
||||
//! GLSL 4.30 Section 8.3). An original probe; the expected values are worked out by hand.
|
||||
use super::destination_tests::Fixture;
|
||||
use super::*;
|
||||
use std::io::{Cursor, Write};
|
||||
|
||||
const VERTEX: &str = "#version 120\nvarying vec2 uv;\nvoid main() { uv=gl_MultiTexCoord0.xy; gl_Position=ftransform(); }\n";
|
||||
|
||||
fn pack() -> Post {
|
||||
let mut zip = zip::ZipWriter::new(Cursor::new(Vec::new()));
|
||||
let mut add = |name: &str, source: &str| {
|
||||
zip.start_file(
|
||||
format!("shaders/{name}"),
|
||||
zip::write::SimpleFileOptions::default(),
|
||||
)
|
||||
.unwrap();
|
||||
zip.write_all(source.as_bytes()).unwrap();
|
||||
};
|
||||
add("final.vsh", VERTEX);
|
||||
// Pixel column x shows case x % 8 in red, green and blue.
|
||||
add(
|
||||
"final.fsh",
|
||||
"#version 330 compatibility\n#extension GL_AMD_shader_trinary_minmax : require\n\
|
||||
void main() {\n int x = int(gl_FragCoord.x) % 8;\n\
|
||||
vec3 a = vec3(0.1, 0.9, 0.4), b = vec3(0.6, 0.2, 0.8), c = vec3(0.3, 0.5, 0.0);\n\
|
||||
ivec3 i = ivec3(-3, 7, 2), j = ivec3(5, -1, 9), k = ivec3(0, 4, -6);\n\
|
||||
uvec3 u = uvec3(1u, 8u, 3u), v = uvec3(6u, 2u, 7u), w = uvec3(4u, 5u, 0u);\n\
|
||||
vec3 o = vec3(0.0);\n\
|
||||
switch (x) {\n\
|
||||
case 0: o = min3(a, b, c); break;\n\
|
||||
case 1: o = max3(a, b, c); break;\n\
|
||||
case 2: o = mid3(a, b, c); break;\n\
|
||||
case 3: o = vec3(mid3(i, j, k)) / 10.0; break;\n\
|
||||
case 4: o = vec3(max3(u, v, w)) / 10.0; break;\n\
|
||||
case 5: o = vec3(min3(i, j, k) + 6) / 10.0; break;\n\
|
||||
case 6: o = vec3(mid3(u.x, v.x, w.x), mid3(u.y, v.y, w.y), mid3(u.z, v.z, w.z)) / 10.0; break;\n\
|
||||
case 7: o = vec3(max3(a.x, b.x, c.x), min3(a.yz, b.yz, c.yz)); break;\n\
|
||||
}\n gl_FragColor = vec4(o, 1.0);\n}\n",
|
||||
);
|
||||
let pack = horizon_shaders::Pack::from_zip_bytes(
|
||||
"original-trinary",
|
||||
zip.finish().unwrap().into_inner(),
|
||||
)
|
||||
.unwrap();
|
||||
let mut macros = horizon_shaders::Macros::standard();
|
||||
let (properties, _) = horizon_shaders::read_properties(&pack, &mut macros);
|
||||
let post = horizon_shaders::load_post(&pack, "", &properties, ¯os, &Default::default());
|
||||
assert_eq!(post.programs.len(), 1, "{:?}", post.notes);
|
||||
post
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn trinary_min_max_and_median_per_component() {
|
||||
let Some(gpu) = Fixture::new() else { return };
|
||||
let mut post = gpu.build(pack());
|
||||
let pixels = gpu.render(&mut post, [8, 8]);
|
||||
// Tenths, by hand: a = (1, 9, 4), b = (6, 2, 8), c = (3, 5, 0); i = (-3, 7, 2),
|
||||
// j = (5, -1, 9), k = (0, 4, -6); u = (1, 8, 3), v = (6, 2, 7), w = (4, 5, 0).
|
||||
let tenths: [[u8; 3]; 8] = [
|
||||
[1, 2, 0],
|
||||
[6, 9, 8],
|
||||
[3, 5, 4],
|
||||
[0, 4, 2],
|
||||
[6, 8, 7],
|
||||
[3, 5, 0],
|
||||
[4, 5, 3],
|
||||
[6, 2, 0],
|
||||
];
|
||||
let row: Vec<[u8; 3]> = pixels[..8].iter().map(|p| [p[0], p[1], p[2]]).collect();
|
||||
for (case, (got, want)) in row.iter().zip(tenths).enumerate() {
|
||||
let want = want.map(|t| (f32::from(t) * 25.5).round() as u8);
|
||||
assert!(
|
||||
got.iter().zip(want).all(|(g, w)| g.abs_diff(w) <= 1),
|
||||
"case {case}: {got:?}, expected {want:?}; row {row:?}"
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -215,16 +215,19 @@ fn pack(
|
||||
T::Rgba8Unorm,
|
||||
World {
|
||||
atlas: None,
|
||||
material_maps: None,
|
||||
lightmap: lightmap.clone(),
|
||||
terrain: None,
|
||||
block_ids: &[],
|
||||
sprite_rects: &[],
|
||||
celestial: None,
|
||||
gui_size: [1, 1],
|
||||
clouds: None,
|
||||
weather: false,
|
||||
hand: false,
|
||||
},
|
||||
);
|
||||
)
|
||||
.expect("the pack runs");
|
||||
assert!(post.notes.is_empty(), "{:?}", post.notes);
|
||||
post
|
||||
}
|
||||
@@ -351,6 +354,7 @@ fn frame(hud: &HudBatch) -> Frame<'_> {
|
||||
celestial: &[],
|
||||
stars: None,
|
||||
hand: &[],
|
||||
hand_items: &[],
|
||||
hand_fov_degrees: 70.0,
|
||||
screen: &[],
|
||||
pack: Default::default(),
|
||||
|
||||
@@ -35,6 +35,13 @@ pub(super) struct ShadowTargets {
|
||||
pub depth: (wgpu::Texture, wgpu::TextureView),
|
||||
/// `shadowtex1`: a copy of `shadowtex0` taken before translucent terrain, when read.
|
||||
pub depth1: Option<(wgpu::Texture, wgpu::TextureView)>,
|
||||
/// `shadowtex0`/`1` as a plain sampler filters them: Iris 1.11.7 reads them linearly unless
|
||||
/// a pack asks for the nearest texel (measured). wgpu filters a depth format only for a
|
||||
/// comparison, so these are `R32Float` copies of the final depths, when read that way.
|
||||
pub linear: [Option<wgpu::TextureView>; 2],
|
||||
/// The rows a depth copy goes through to `linear` (a depth format copies only to a buffer),
|
||||
/// and their stride in bytes.
|
||||
staging: Option<(wgpu::Buffer, u32)>,
|
||||
/// Both sides of each shadowcolor buffer used.
|
||||
pub color: [Option<[wgpu::TextureView; 2]>; SHADOW_COLORS],
|
||||
/// The clear colour of each buffer cleared every frame.
|
||||
@@ -77,13 +84,15 @@ fn target(
|
||||
|
||||
impl ShadowTargets {
|
||||
/// The buffers of `shadow` the pack uses: `colors` (bit n: shadowcolor n), `depth1` when
|
||||
/// some program reads `shadowtex1`. The resolution is kept within the device's limit.
|
||||
/// some program reads `shadowtex1`, `linear` (bit n: shadowtex n read through a filtering
|
||||
/// sampler). The resolution is kept within the device's limit.
|
||||
pub fn new(
|
||||
device: &wgpu::Device,
|
||||
shadow: &horizon_shaders::Shadow,
|
||||
formats: [wgpu::TextureFormat; SHADOW_COLORS],
|
||||
colors: u16,
|
||||
depth1: bool,
|
||||
linear: u8,
|
||||
) -> Self {
|
||||
let size = shadow
|
||||
.resolution
|
||||
@@ -105,10 +114,43 @@ impl ShadowTargets {
|
||||
})
|
||||
})
|
||||
});
|
||||
let linear = [0, 1].map(|n| {
|
||||
(linear & 1 << n != 0).then(|| {
|
||||
let label = format!("Shader pack shadowtex{n} (filtered)");
|
||||
device
|
||||
.create_texture(&wgpu::TextureDescriptor {
|
||||
label: Some(&label),
|
||||
size: wgpu::Extent3d {
|
||||
width: size,
|
||||
height: size,
|
||||
depth_or_array_layers: 1,
|
||||
},
|
||||
mip_level_count: 1,
|
||||
sample_count: 1,
|
||||
dimension: wgpu::TextureDimension::D2,
|
||||
format: wgpu::TextureFormat::R32Float,
|
||||
usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
|
||||
view_formats: &[],
|
||||
})
|
||||
.create_view(&Default::default())
|
||||
})
|
||||
});
|
||||
let staging = linear.iter().any(Option::is_some).then(|| {
|
||||
let stride = (size * 4).next_multiple_of(wgpu::COPY_BYTES_PER_ROW_ALIGNMENT);
|
||||
let buffer = device.create_buffer(&wgpu::BufferDescriptor {
|
||||
label: Some("Shader pack shadow depth rows"),
|
||||
size: u64::from(stride) * u64::from(size),
|
||||
usage: wgpu::BufferUsages::COPY_SRC | wgpu::BufferUsages::COPY_DST,
|
||||
mapped_at_creation: false,
|
||||
});
|
||||
(buffer, stride)
|
||||
});
|
||||
Self {
|
||||
size,
|
||||
depth: target(device, "Shader pack shadowtex0", size, depth, copy),
|
||||
depth1: depth1.then(|| target(device, "Shader pack shadowtex1", size, depth, copy)),
|
||||
linear,
|
||||
staging,
|
||||
color,
|
||||
clears: std::array::from_fn(|n| {
|
||||
let b = &shadow.colors[n];
|
||||
@@ -214,4 +256,38 @@ impl ShadowTargets {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// `linear`: the filtered copies of the depths the shadow pass left (`shadowtex1` from its
|
||||
/// copy before translucent geometry).
|
||||
pub fn copy_linear(&self, encoder: &mut wgpu::CommandEncoder) {
|
||||
let Some((buffer, stride)) = &self.staging else {
|
||||
return;
|
||||
};
|
||||
for (n, linear) in self.linear.iter().enumerate() {
|
||||
let Some(linear) = linear else {
|
||||
continue;
|
||||
};
|
||||
let depth = match (n, &self.depth1) {
|
||||
(1, Some(d)) => &d.0,
|
||||
_ => &self.depth.0,
|
||||
};
|
||||
let rows = wgpu::TexelCopyBufferInfo {
|
||||
buffer,
|
||||
layout: wgpu::TexelCopyBufferLayout {
|
||||
offset: 0,
|
||||
bytes_per_row: Some(*stride),
|
||||
rows_per_image: None,
|
||||
},
|
||||
};
|
||||
encoder.copy_texture_to_buffer(
|
||||
wgpu::TexelCopyTextureInfo {
|
||||
aspect: wgpu::TextureAspect::DepthOnly,
|
||||
..depth.as_image_copy()
|
||||
},
|
||||
rows,
|
||||
depth.size(),
|
||||
);
|
||||
encoder.copy_buffer_to_texture(rows, linear.texture().as_image_copy(), depth.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -97,6 +97,7 @@ pub fn inputs() -> horizon_shaders::GbuffersInputs {
|
||||
// At the far plane: the sky shows only where nothing else drew, and it writes no depth.
|
||||
after: " gl_Position.z = gl_Position.w;\n".into(),
|
||||
alpha_test: None,
|
||||
item_id_declared: false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,6 +123,7 @@ pub fn celestial_inputs() -> horizon_shaders::GbuffersInputs {
|
||||
],
|
||||
after: " gl_Position.z = gl_Position.w;\n".into(),
|
||||
alpha_test: None,
|
||||
item_id_declared: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,8 @@ pub(super) struct PackTexture {
|
||||
pub(super) sample_type: wgpu::TextureSampleType,
|
||||
pub(super) blur: bool,
|
||||
pub(super) clamp: bool,
|
||||
/// Decoded from a PNG, the pack's or the game's (not a raw dump, not a generated texture).
|
||||
pub(super) png: bool,
|
||||
pub(super) image: Image,
|
||||
}
|
||||
|
||||
@@ -30,7 +32,7 @@ pub(super) fn upload(
|
||||
let features = device.features();
|
||||
let mut out = Vec::new();
|
||||
for t in textures {
|
||||
let (image, dimension, sample_type, blur, clamp) = match t.source {
|
||||
let (image, dimension, sample_type, blur, clamp, png) = match t.source {
|
||||
TextureSource::Image(texture) => {
|
||||
let (view, sample_type) = match create(device, queue, &texture, features) {
|
||||
Ok(created) => created,
|
||||
@@ -50,6 +52,7 @@ pub(super) fn upload(
|
||||
sample_type,
|
||||
texture.blur,
|
||||
texture.clamp,
|
||||
!texture.raw,
|
||||
)
|
||||
}
|
||||
TextureSource::Resource(location) => {
|
||||
@@ -66,7 +69,14 @@ pub(super) fn upload(
|
||||
continue;
|
||||
};
|
||||
let float = wgpu::TextureSampleType::Float { filterable: true };
|
||||
(image, wgpu::TextureViewDimension::D2, float, true, true)
|
||||
(
|
||||
image,
|
||||
wgpu::TextureViewDimension::D2,
|
||||
float,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
)
|
||||
}
|
||||
};
|
||||
out.push(PackTexture {
|
||||
@@ -76,6 +86,7 @@ pub(super) fn upload(
|
||||
sample_type,
|
||||
blur,
|
||||
clamp,
|
||||
png,
|
||||
image,
|
||||
});
|
||||
}
|
||||
@@ -285,6 +296,7 @@ mod tests {
|
||||
sample_type: wgpu::TextureSampleType::Float { filterable: true },
|
||||
blur: false,
|
||||
clamp: false,
|
||||
png: false,
|
||||
image: Image::Lightmap,
|
||||
}
|
||||
}
|
||||
@@ -297,6 +309,7 @@ mod tests {
|
||||
texels,
|
||||
blur: false,
|
||||
clamp: false,
|
||||
raw: true,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1029,11 +1029,6 @@ mod initial_history_tests {
|
||||
#[test]
|
||||
#[ignore = "requires a host GPU; run with --ignored --nocapture"]
|
||||
fn core_matrix_inputs_render_provider_values() {
|
||||
use horizon_shaders::{
|
||||
GbuffersInputs, Macros, Pack, Target, preprocess, translate_gbuffers,
|
||||
};
|
||||
use std::io::Write;
|
||||
use wgpu::util::DeviceExt;
|
||||
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor::new_without_display_handle());
|
||||
let adapter = pollster::block_on(instance.request_adapter(&Default::default())).unwrap();
|
||||
eprintln!("Core matrix GPU: {:?}", adapter.get_info());
|
||||
@@ -1093,137 +1088,7 @@ mod initial_history_tests {
|
||||
vec2 p = vec2((gl_VertexID << 1) & 2, gl_VertexID & 2);\n\
|
||||
gl_Position = vec4(p * 2.0 - 1.0, 0.0, 1.0);\n}}"
|
||||
);
|
||||
let mut zip = zip::ZipWriter::new(std::io::Cursor::new(Vec::new()));
|
||||
for (path, source) in [
|
||||
("shaders/gbuffers_line.vsh", vertex.as_str()),
|
||||
(
|
||||
"shaders/gbuffers_line.fsh",
|
||||
"#version 330\nin vec3 result; out vec4 color; void main() { color = vec4(result, 1.0); }",
|
||||
),
|
||||
] {
|
||||
zip.start_file(path, zip::write::SimpleFileOptions::default())
|
||||
.unwrap();
|
||||
zip.write_all(source.as_bytes()).unwrap();
|
||||
}
|
||||
let pack = Pack::from_zip_bytes("matrix-probe.zip", zip.finish().unwrap().into_inner())
|
||||
.unwrap();
|
||||
let macros = Macros::standard();
|
||||
let program = translate_gbuffers(
|
||||
&preprocess(&pack, "gbuffers_line.vsh", ¯os),
|
||||
&preprocess(&pack, "gbuffers_line.fsh", ¯os),
|
||||
Target::Buffers,
|
||||
&GbuffersInputs::default(),
|
||||
)
|
||||
.unwrap();
|
||||
let mut bytes = vec![0; program.interface.uniform_size as usize];
|
||||
for uniform in &program.interface.uniforms {
|
||||
if let Some(i) = index(&uniform.name) {
|
||||
values.values[i].write(&uniform.ty, &mut bytes, uniform.offset as usize);
|
||||
}
|
||||
}
|
||||
let uniform = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||
label: None,
|
||||
contents: &bytes,
|
||||
usage: wgpu::BufferUsages::UNIFORM,
|
||||
});
|
||||
let module = |module| {
|
||||
device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
||||
label: None,
|
||||
source: wgpu::ShaderSource::Naga(std::borrow::Cow::Owned(module)),
|
||||
})
|
||||
};
|
||||
let vs = module(program.vertex);
|
||||
let fs = module(program.fragment);
|
||||
let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||
label: None,
|
||||
layout: None,
|
||||
vertex: wgpu::VertexState {
|
||||
module: &vs,
|
||||
entry_point: Some("main"),
|
||||
compilation_options: Default::default(),
|
||||
buffers: &[],
|
||||
},
|
||||
primitive: Default::default(),
|
||||
depth_stencil: None,
|
||||
multisample: Default::default(),
|
||||
fragment: Some(wgpu::FragmentState {
|
||||
module: &fs,
|
||||
entry_point: Some("main"),
|
||||
compilation_options: Default::default(),
|
||||
targets: &[Some(wgpu::ColorTargetState {
|
||||
format: wgpu::TextureFormat::Rgba8Unorm,
|
||||
blend: None,
|
||||
write_mask: wgpu::ColorWrites::ALL,
|
||||
})],
|
||||
}),
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
let group = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||
label: None,
|
||||
layout: &pipeline.get_bind_group_layout(0),
|
||||
entries: &[wgpu::BindGroupEntry {
|
||||
binding: 0,
|
||||
resource: uniform.as_entire_binding(),
|
||||
}],
|
||||
});
|
||||
let texture = device.create_texture(&wgpu::TextureDescriptor {
|
||||
label: None,
|
||||
size: wgpu::Extent3d {
|
||||
width: 1,
|
||||
height: 1,
|
||||
depth_or_array_layers: 1,
|
||||
},
|
||||
mip_level_count: 1,
|
||||
sample_count: 1,
|
||||
dimension: wgpu::TextureDimension::D2,
|
||||
format: wgpu::TextureFormat::Rgba8Unorm,
|
||||
usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_SRC,
|
||||
view_formats: &[],
|
||||
});
|
||||
let view = texture.create_view(&Default::default());
|
||||
let read = device.create_buffer(&wgpu::BufferDescriptor {
|
||||
label: None,
|
||||
size: 256,
|
||||
usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::MAP_READ,
|
||||
mapped_at_creation: false,
|
||||
});
|
||||
let mut encoder = device.create_command_encoder(&Default::default());
|
||||
{
|
||||
let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||
label: None,
|
||||
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
||||
view: &view,
|
||||
resolve_target: None,
|
||||
depth_slice: None,
|
||||
ops: wgpu::Operations {
|
||||
load: wgpu::LoadOp::Clear(wgpu::Color::BLACK),
|
||||
store: wgpu::StoreOp::Store,
|
||||
},
|
||||
})],
|
||||
..Default::default()
|
||||
});
|
||||
pass.set_pipeline(&pipeline);
|
||||
pass.set_bind_group(0, &group, &[]);
|
||||
pass.draw(0..3, 0..1);
|
||||
}
|
||||
encoder.copy_texture_to_buffer(
|
||||
texture.as_image_copy(),
|
||||
wgpu::TexelCopyBufferInfo {
|
||||
buffer: &read,
|
||||
layout: wgpu::TexelCopyBufferLayout {
|
||||
offset: 0,
|
||||
bytes_per_row: Some(256),
|
||||
rows_per_image: None,
|
||||
},
|
||||
},
|
||||
texture.size(),
|
||||
);
|
||||
queue.submit([encoder.finish()]);
|
||||
read.slice(..)
|
||||
.map_async(wgpu::MapMode::Read, |result| result.unwrap());
|
||||
device.poll(wgpu::PollType::wait_indefinitely()).unwrap();
|
||||
let mapped = read.slice(..).get_mapped_range().unwrap();
|
||||
let mapped = draw_line_program(&device, &queue, &values, &vertex);
|
||||
// Independent result: translated point (1, .5, -2), perspective (aspect 2,
|
||||
// vertical FOV 90): clip (.5, .5, z, 2), hence (.25, .25, .5, 1).
|
||||
for (actual, expected) in mapped[..4].iter().zip(expected) {
|
||||
@@ -1236,6 +1101,203 @@ mod initial_history_tests {
|
||||
}
|
||||
}
|
||||
|
||||
/// `normalMatrix` in a core-profile gbuffers program is the view's rotation; in the
|
||||
/// compatibility profile it stays zero (the issue's Iris 1.11.7 probes, #9136).
|
||||
#[test]
|
||||
#[ignore = "requires a host GPU; run with --ignored --nocapture"]
|
||||
fn core_normal_matrix_renders_the_view_rotation() {
|
||||
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor::new_without_display_handle());
|
||||
let adapter = pollster::block_on(instance.request_adapter(&Default::default())).unwrap();
|
||||
eprintln!("Normal matrix GPU: {:?}", adapter.get_info());
|
||||
let (device, queue) =
|
||||
pollster::block_on(adapter.request_device(&Default::default())).unwrap();
|
||||
let hud = HudBatch::new([800, 400]);
|
||||
let mut f = frame(&hud);
|
||||
// Facing west (-X), level: view space looks down -Z with +X to the right (north).
|
||||
f.yaw = 90.0;
|
||||
f.pitch = 0.0;
|
||||
let mut values = FrameUniforms::default();
|
||||
values.update(&f, &PackInputs::default(), [800, 400]);
|
||||
for (profile, world, expected) in [
|
||||
// East (behind the camera) is view +Z.
|
||||
("330 core", "vec3(1.0, 0.0, 0.0)", [128u8, 128, 255, 255]),
|
||||
// South (to the left) is view -X; up stays up.
|
||||
("330 core", "vec3(0.0, 0.0, 1.0)", [0, 128, 128, 255]),
|
||||
("330 core", "vec3(0.0, 1.0, 0.0)", [128, 255, 128, 255]),
|
||||
(
|
||||
"330 compatibility",
|
||||
"vec3(1.0, 0.0, 0.0)",
|
||||
[128, 128, 128, 255],
|
||||
),
|
||||
] {
|
||||
let vertex = format!(
|
||||
"#version {profile}\nuniform mat3 normalMatrix;\nout vec3 result;\n\
|
||||
void main() {{\n\
|
||||
result = normalMatrix * {world} * 0.5 + 0.5;\n\
|
||||
vec2 p = vec2((gl_VertexID << 1) & 2, gl_VertexID & 2);\n\
|
||||
gl_Position = vec4(p * 2.0 - 1.0, 0.0, 1.0);\n}}"
|
||||
);
|
||||
let pixel = draw_line_program(&device, &queue, &values, &vertex);
|
||||
eprintln!("{profile} {world}: {pixel:?}");
|
||||
for (actual, expected) in pixel.iter().zip(expected) {
|
||||
assert!(
|
||||
actual.abs_diff(expected) <= 1,
|
||||
"{profile} {world}: {pixel:?}"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Draws one fragment through a translated `gbuffers_line` program with `vertex` and the
|
||||
/// provider's `values`, and reads it back.
|
||||
fn draw_line_program(
|
||||
device: &wgpu::Device,
|
||||
queue: &wgpu::Queue,
|
||||
values: &FrameUniforms,
|
||||
vertex: &str,
|
||||
) -> [u8; 4] {
|
||||
use horizon_shaders::{
|
||||
GbuffersInputs, Macros, Pack, Target, preprocess, translate_gbuffers,
|
||||
};
|
||||
use std::io::Write;
|
||||
use wgpu::util::DeviceExt;
|
||||
let mut zip = zip::ZipWriter::new(std::io::Cursor::new(Vec::new()));
|
||||
for (path, source) in [
|
||||
("shaders/gbuffers_line.vsh", vertex),
|
||||
(
|
||||
"shaders/gbuffers_line.fsh",
|
||||
"#version 330\nin vec3 result; out vec4 color; void main() { color = vec4(result, 1.0); }",
|
||||
),
|
||||
] {
|
||||
zip.start_file(path, zip::write::SimpleFileOptions::default())
|
||||
.unwrap();
|
||||
zip.write_all(source.as_bytes()).unwrap();
|
||||
}
|
||||
let pack =
|
||||
Pack::from_zip_bytes("matrix-probe.zip", zip.finish().unwrap().into_inner()).unwrap();
|
||||
let macros = Macros::standard();
|
||||
let program = translate_gbuffers(
|
||||
&preprocess(&pack, "gbuffers_line.vsh", ¯os),
|
||||
&preprocess(&pack, "gbuffers_line.fsh", ¯os),
|
||||
Target::Buffers,
|
||||
&GbuffersInputs::default(),
|
||||
)
|
||||
.unwrap();
|
||||
let mut bytes = vec![0; program.interface.uniform_size as usize];
|
||||
for uniform in &program.interface.uniforms {
|
||||
if let Some(i) = index(&uniform.name) {
|
||||
values.values[i].write(&uniform.ty, &mut bytes, uniform.offset as usize);
|
||||
}
|
||||
}
|
||||
let uniform = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||
label: None,
|
||||
contents: &bytes,
|
||||
usage: wgpu::BufferUsages::UNIFORM,
|
||||
});
|
||||
let module = |module| {
|
||||
device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
||||
label: None,
|
||||
source: wgpu::ShaderSource::Naga(std::borrow::Cow::Owned(module)),
|
||||
})
|
||||
};
|
||||
let vs = module(program.vertex);
|
||||
let fs = module(program.fragment);
|
||||
let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||
label: None,
|
||||
layout: None,
|
||||
vertex: wgpu::VertexState {
|
||||
module: &vs,
|
||||
entry_point: Some("main"),
|
||||
compilation_options: Default::default(),
|
||||
buffers: &[],
|
||||
},
|
||||
primitive: Default::default(),
|
||||
depth_stencil: None,
|
||||
multisample: Default::default(),
|
||||
fragment: Some(wgpu::FragmentState {
|
||||
module: &fs,
|
||||
entry_point: Some("main"),
|
||||
compilation_options: Default::default(),
|
||||
targets: &[Some(wgpu::ColorTargetState {
|
||||
format: wgpu::TextureFormat::Rgba8Unorm,
|
||||
blend: None,
|
||||
write_mask: wgpu::ColorWrites::ALL,
|
||||
})],
|
||||
}),
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
let group = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||
label: None,
|
||||
layout: &pipeline.get_bind_group_layout(0),
|
||||
entries: &[wgpu::BindGroupEntry {
|
||||
binding: 0,
|
||||
resource: uniform.as_entire_binding(),
|
||||
}],
|
||||
});
|
||||
let texture = device.create_texture(&wgpu::TextureDescriptor {
|
||||
label: None,
|
||||
size: wgpu::Extent3d {
|
||||
width: 1,
|
||||
height: 1,
|
||||
depth_or_array_layers: 1,
|
||||
},
|
||||
mip_level_count: 1,
|
||||
sample_count: 1,
|
||||
dimension: wgpu::TextureDimension::D2,
|
||||
format: wgpu::TextureFormat::Rgba8Unorm,
|
||||
usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_SRC,
|
||||
view_formats: &[],
|
||||
});
|
||||
let view = texture.create_view(&Default::default());
|
||||
let read = device.create_buffer(&wgpu::BufferDescriptor {
|
||||
label: None,
|
||||
size: 256,
|
||||
usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::MAP_READ,
|
||||
mapped_at_creation: false,
|
||||
});
|
||||
let mut encoder = device.create_command_encoder(&Default::default());
|
||||
{
|
||||
let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||
label: None,
|
||||
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
||||
view: &view,
|
||||
resolve_target: None,
|
||||
depth_slice: None,
|
||||
ops: wgpu::Operations {
|
||||
load: wgpu::LoadOp::Clear(wgpu::Color::BLACK),
|
||||
store: wgpu::StoreOp::Store,
|
||||
},
|
||||
})],
|
||||
..Default::default()
|
||||
});
|
||||
pass.set_pipeline(&pipeline);
|
||||
pass.set_bind_group(0, &group, &[]);
|
||||
pass.draw(0..3, 0..1);
|
||||
}
|
||||
encoder.copy_texture_to_buffer(
|
||||
texture.as_image_copy(),
|
||||
wgpu::TexelCopyBufferInfo {
|
||||
buffer: &read,
|
||||
layout: wgpu::TexelCopyBufferLayout {
|
||||
offset: 0,
|
||||
bytes_per_row: Some(256),
|
||||
rows_per_image: None,
|
||||
},
|
||||
},
|
||||
texture.size(),
|
||||
);
|
||||
queue.submit([encoder.finish()]);
|
||||
read.slice(..)
|
||||
.map_async(wgpu::MapMode::Read, |result| result.unwrap());
|
||||
device.poll(wgpu::PollType::wait_indefinitely()).unwrap();
|
||||
let mapped = read.slice(..).get_mapped_range().unwrap();
|
||||
let pixel = mapped[..4].try_into().unwrap();
|
||||
drop(mapped);
|
||||
read.unmap();
|
||||
pixel
|
||||
}
|
||||
|
||||
fn int(u: &FrameUniforms, at: usize) -> i32 {
|
||||
match u.values[at] {
|
||||
Value::I(v) => v[0],
|
||||
@@ -1411,6 +1473,7 @@ mod initial_history_tests {
|
||||
celestial: &[],
|
||||
stars: None,
|
||||
hand: &[],
|
||||
hand_items: &[],
|
||||
hand_fov_degrees: 70.0,
|
||||
screen: &[],
|
||||
pack: Default::default(),
|
||||
|
||||
@@ -44,6 +44,7 @@ pub fn inputs() -> horizon_shaders::GbuffersInputs {
|
||||
op: ">",
|
||||
reference: 0.1,
|
||||
}),
|
||||
item_id_declared: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -67,6 +67,17 @@ impl Readback {
|
||||
let Some(texture) = self.texture.clone() else {
|
||||
return;
|
||||
};
|
||||
self.draw_onto(device, encoder, &texture, surface);
|
||||
}
|
||||
|
||||
/// Draws `frame` onto the swapchain image (or offscreen target) `surface`.
|
||||
pub fn draw_onto(
|
||||
&mut self,
|
||||
device: &wgpu::Device,
|
||||
encoder: &mut wgpu::CommandEncoder,
|
||||
frame: &wgpu::Texture,
|
||||
surface: &wgpu::Texture,
|
||||
) {
|
||||
// The frame's passes write the swapchain through its non-sRGB view
|
||||
// (`view_formats`), so the copy goes there unconverted too.
|
||||
let format = surface.format().remove_srgb_suffix();
|
||||
@@ -74,7 +85,7 @@ impl Readback {
|
||||
format: Some(format),
|
||||
..Default::default()
|
||||
});
|
||||
self.blit(device, encoder, &texture, &target, format);
|
||||
self.blit(device, encoder, frame, &target, format);
|
||||
}
|
||||
|
||||
/// `frame` (a 16-bit frame) in an 8-bit texture of `format`, clamped to 0..1
|
||||
|
||||
@@ -92,7 +92,7 @@ impl<T> Resident<T> {
|
||||
self.items.iter_mut().map(|(_, v)| v)
|
||||
}
|
||||
/// Every section's key, value and bounds.
|
||||
#[cfg(debug_assertions)]
|
||||
#[cfg(any(test, debug_assertions))]
|
||||
pub fn iter(&self) -> impl Iterator<Item = (SectionKey, &T, Option<[Vec3; 2]>)> {
|
||||
let items = self.items.iter().zip(&self.bounds);
|
||||
items.map(|((key, value), bounds)| (*key, value, *bounds))
|
||||
@@ -194,6 +194,12 @@ impl<T> Resident<T> {
|
||||
column.low = column.low.min(key.1);
|
||||
column.high = column.high.max(key.1);
|
||||
}
|
||||
/// Marks or unmarks the section at `key`, if it is resident.
|
||||
pub fn set_marked(&mut self, key: SectionKey, marked: bool) {
|
||||
if let Some(&slot) = self.slots.get(&key) {
|
||||
self.mark_slot(slot, marked);
|
||||
}
|
||||
}
|
||||
/// Marks or unmarks the section in `slot`, in its column's list too.
|
||||
fn mark_slot(&mut self, slot: u32, marked: bool) {
|
||||
let was = std::mem::replace(&mut self.marked[slot as usize], marked);
|
||||
@@ -657,7 +663,8 @@ mod tests {
|
||||
(!value.is_multiple_of(3)).then(|| [Vec3::splat((value % 5) as f32), Vec3::splat(16.0)])
|
||||
};
|
||||
// A deterministic mix of inserts, replacements and removals, marked at
|
||||
// random: a replacement can mark or unmark its section.
|
||||
// random: a replacement can mark or unmark its section, and so can a
|
||||
// mark set alone (`set_marked`), which leaves a key not resident alone.
|
||||
let mut seed = 0x2545_f491_u32;
|
||||
for step in 0..4000u32 {
|
||||
seed ^= seed << 13;
|
||||
@@ -694,6 +701,12 @@ mod tests {
|
||||
assert_eq!(removed, expected);
|
||||
} else if (seed >> 12).is_multiple_of(3) {
|
||||
assert_eq!(r.remove(key), model.remove(&key).map(|(value, _)| value));
|
||||
} else if (seed >> 12).is_multiple_of(5) {
|
||||
let marked = (seed >> 20).is_multiple_of(2);
|
||||
r.set_marked(key, marked);
|
||||
if let Some(held) = model.get_mut(&key) {
|
||||
held.1 = marked;
|
||||
}
|
||||
} else {
|
||||
let marked = (seed >> 20).is_multiple_of(2);
|
||||
r.insert_marked(key, step, bounds(step), marked);
|
||||
|
||||
@@ -1050,7 +1050,9 @@ impl Item {
|
||||
Item::Horizon(H::Hdr) => g.hdr,
|
||||
Item::Horizon(H::BatteryMode) => g.battery,
|
||||
Item::Horizon(H::ShadowCache) => g.shadow_cache,
|
||||
Item::Horizon(H::TranslucentBatching) => g.translucent_batching,
|
||||
Item::Horizon(H::TranslucentBatching) => {
|
||||
g.translucent_batching && crate::graphics::translucent_batching_offered()
|
||||
}
|
||||
Item::Horizon(H::HdrSmoothGradients) => {
|
||||
g.hdr_smooth_gradients && crate::graphics::smooth_gradients_offered()
|
||||
}
|
||||
@@ -3164,13 +3166,13 @@ mod tests {
|
||||
assert_eq!(page, Some(Page::Advanced));
|
||||
let mut s = Settings::default();
|
||||
s.horizon.preset = Preset::Balanced;
|
||||
assert_eq!(item.switch(&s), Some(true));
|
||||
let mut ui = GraphicsUi::default();
|
||||
// Where the device can't, the saved On reads Off, and neither a click nor Enter
|
||||
// after it does anything: no sound, no change, no save.
|
||||
crate::graphics::offer_translucent_batching(false);
|
||||
assert!(item.blocked(&s).is_some());
|
||||
assert_eq!(item.label(&s).plain(), "Translucent Batching: Off");
|
||||
assert_eq!(item.switch(&s), Some(false));
|
||||
let r = row(&mut ui, &s, item);
|
||||
let point = (r[0] + 4.0, r[1] + 4.0);
|
||||
assert!(press(&mut ui, &mut s, point).is_empty());
|
||||
@@ -3181,6 +3183,7 @@ mod tests {
|
||||
// Where it can, a click switches it and keeps the preset.
|
||||
crate::graphics::offer_translucent_batching(true);
|
||||
assert_eq!(item.label(&s).plain(), "Translucent Batching: On");
|
||||
assert_eq!(item.switch(&s), Some(true));
|
||||
assert_eq!(
|
||||
press(&mut ui, &mut s, point),
|
||||
[Action::ButtonClick, Action::Changed]
|
||||
|
||||
@@ -796,10 +796,10 @@ impl HudAtlas {
|
||||
let g = self.font.glyph(ch);
|
||||
g.rect.map(|rect| (rect, g.advance))
|
||||
}
|
||||
/// A font glyph's atlas cell (none for blank glyphs such as the space) and advance.
|
||||
pub fn glyph_cell(&self, ch: char) -> (Option<Rect>, f32) {
|
||||
let g = self.font.glyph(ch);
|
||||
(g.rect, g.advance)
|
||||
/// A font glyph in the default font: its atlas cell (none for blank
|
||||
/// glyphs such as the space), its box and advance.
|
||||
pub fn glyph_cell(&self, ch: char) -> crate::font::Glyph {
|
||||
self.font.glyph(ch)
|
||||
}
|
||||
pub fn build(root: &Path) -> Result<Self> {
|
||||
Self::build_over(root, root)
|
||||
@@ -887,13 +887,39 @@ impl HudAtlas {
|
||||
));
|
||||
}
|
||||
/// Only the font's metrics, for a game that draws nothing (the
|
||||
/// integrated server): text measures as with the full atlas, without
|
||||
/// holding its textures. The pixels are dropped once the glyph widths are
|
||||
/// read, since nothing uploads them.
|
||||
/// integrated or dedicated server): text measures as with the full atlas,
|
||||
/// without packing textures or rasterizing glyphs.
|
||||
pub fn fonts(root: &Path) -> Result<Self> {
|
||||
let mut atlas = Self::pack(root, root, &["font"], false, false)?;
|
||||
atlas.pixels = Vec::new();
|
||||
Ok(atlas)
|
||||
let white = Rect {
|
||||
u0: 0.0,
|
||||
v0: 0.0,
|
||||
u1: 1.0,
|
||||
v1: 1.0,
|
||||
w: 1,
|
||||
h: 1,
|
||||
};
|
||||
Ok(Self {
|
||||
revision: Self::next_revision(),
|
||||
pixels: Vec::new(),
|
||||
packed: None,
|
||||
galactic_widths: [0; 128],
|
||||
width: 1,
|
||||
height: 1,
|
||||
sprites: HashMap::new(),
|
||||
object_skins: HashMap::new(),
|
||||
translucent: HashSet::new(),
|
||||
flags: HashMap::new(),
|
||||
sprite_animations: Vec::new(),
|
||||
font: crate::font::Font::metrics(root),
|
||||
glint: (Vec::new(), 1, 1),
|
||||
glint_armor: (Vec::new(), 1, 1),
|
||||
text_shader: None,
|
||||
lines_shader: None,
|
||||
random_textures: Default::default(),
|
||||
emissive: Arc::default(),
|
||||
blinks: Default::default(),
|
||||
white,
|
||||
})
|
||||
}
|
||||
/// The boot screen's atlas, before any pack loads: the theme's run-time
|
||||
/// glyphs (`horizon/ui-text`), a white sprite and the glyph rows over
|
||||
@@ -1274,6 +1300,12 @@ impl HudAtlas {
|
||||
edition.3 = pixels;
|
||||
}
|
||||
images.push(("horizon/white".into(), 4, 4, vec![255; 64]));
|
||||
images.push((
|
||||
crate::pad_cursor::SPRITE.into(),
|
||||
crate::pad_cursor::SIZE,
|
||||
crate::pad_cursor::SIZE,
|
||||
crate::pad_cursor::pixels(),
|
||||
));
|
||||
if full {
|
||||
Self::slots(&mut images, crate::trims::slot_size(root), mod_image);
|
||||
// MissingTextureAtlasSprite.generateMissingImage: 16x16, magenta
|
||||
|
||||
@@ -74,6 +74,7 @@ pub mod overlay;
|
||||
pub mod pack_browser;
|
||||
pub mod pack_screen;
|
||||
pub mod packs;
|
||||
pub mod pad_cursor;
|
||||
pub mod par;
|
||||
pub mod particles;
|
||||
pub mod poi_sections;
|
||||
|
||||
@@ -77,6 +77,110 @@ const HELD_SAMPLE_STEP: std::time::Duration = std::time::Duration::from_millis(5
|
||||
/// How long a tile whose sampling failed (`LodSampler::grid` gave no
|
||||
/// columns: a server refused or lost it) waits before it is asked again.
|
||||
const RETRY: std::time::Duration = std::time::Duration::from_secs(2);
|
||||
/// The most a tile a zoomed view magnifies may split past the plan it would
|
||||
/// have had ([`ZoomAim`]): cells three times smaller, so nine times the tiles
|
||||
/// where it applies. A spyglass covers about a sixteenth of the circle, so at
|
||||
/// the 4078 tiles and ~1500 quads a tile measured at `lodDistance` 256 this
|
||||
/// asks for roughly 45% more far tiles while the zoom is held, and gives them
|
||||
/// back when it is released. Four would be about 85%: raise it only with a
|
||||
/// measurement, because the cost grows with the square.
|
||||
const MAX_ZOOM_BOOST: i32 = 3;
|
||||
/// Yaw is rounded to this many degrees before it reaches the plan, so turning
|
||||
/// the mouse does not rebuild the quadtree every frame. The cone is widened by
|
||||
/// as much, so rounding never swings it off a tile being looked at.
|
||||
const ZOOM_YAW_STEP: f32 = 5.0;
|
||||
|
||||
/// Where a zoomed view asks for finer far tiles (the `lodZoomDetail` extra).
|
||||
///
|
||||
/// `Plan::visit`'s falloff keeps a tile's cells roughly the same size on
|
||||
/// screen, which silently assumes the field of view never changes. A spyglass
|
||||
/// (`SpyglassItem`, a tenth of it) or the zoom mod breaks that: the same tile
|
||||
/// covers many times more pixels, so its cells look as coarse as a tile ten
|
||||
/// times nearer would. This asks the tiles the zoom actually magnifies to
|
||||
/// split further.
|
||||
///
|
||||
/// Only those: lifting the whole circle would ask for about a hundred times
|
||||
/// the tiles, which at the quads measured above is gigabytes of vertices. The
|
||||
/// cone is the narrowed view's, and `MAX_ZOOM_BOOST` caps how far it goes.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub struct ZoomAim {
|
||||
/// The view direction in x/z, in thousandths of a unit vector.
|
||||
dir: [i32; 2],
|
||||
/// The cosine of the cone's half-angle, in thousandths.
|
||||
cos_half: i32,
|
||||
/// How many times further than the unzoomed plan a tile inside the cone
|
||||
/// may split. Two or more; [`ZoomAim::new`] gives `None` for less.
|
||||
boost: i32,
|
||||
}
|
||||
|
||||
impl ZoomAim {
|
||||
/// `fov_degrees` is the zoomed field of view and `magnification` how many
|
||||
/// times the view is magnified (1 when it is not). `None` when the zoom is
|
||||
/// too slight to be worth replanning for.
|
||||
pub fn new(yaw: f32, fov_degrees: f32, magnification: f32) -> Option<Self> {
|
||||
if !magnification.is_finite() || !fov_degrees.is_finite() || fov_degrees <= 0.0 {
|
||||
return None;
|
||||
}
|
||||
let boost = (magnification.round() as i64).clamp(1, i64::from(MAX_ZOOM_BOOST)) as i32;
|
||||
if boost < 2 {
|
||||
return None;
|
||||
}
|
||||
// Half the field of view spans the screen's width; three quarters of
|
||||
// it reaches the corners, and the rounding step is added on top.
|
||||
let half = (fov_degrees * 0.75 + ZOOM_YAW_STEP).clamp(5.0, 90.0);
|
||||
let radians = ((yaw / ZOOM_YAW_STEP).round() * ZOOM_YAW_STEP).to_radians();
|
||||
// `view_vector`'s x and z: yaw 0 looks toward +z.
|
||||
let thousandths = |v: f32| (v * 1000.0).round() as i32;
|
||||
Some(Self {
|
||||
dir: [thousandths(-radians.sin()), thousandths(radians.cos())],
|
||||
cos_half: thousandths(half.to_radians().cos()),
|
||||
boost,
|
||||
})
|
||||
}
|
||||
/// Whether the cone reaches `key`, so the zoom magnifies it.
|
||||
///
|
||||
/// The tile is taken as the circle around its centre that covers it, and
|
||||
/// that circle's own angular radius widens the cone for the test, so a
|
||||
/// tile straddling the edge counts in rather than out. A tile whose circle
|
||||
/// reaches the camera is always in: there is no direction to compare, and
|
||||
/// it fills the view whichever way the player faces.
|
||||
fn covers(&self, key: TileKey, camera: [i32; 2]) -> bool {
|
||||
let [ox, _, oz] = key.origin();
|
||||
let size = key.size();
|
||||
// The camera stands in the tile: it is in view whichever way the
|
||||
// player faces, and there is no direction to compare it with. Tested
|
||||
// on the box rather than on the circle below, whose radius a camera
|
||||
// on a corner matches exactly -- a float coin-toss.
|
||||
// In i64: a level 22 tile is 67 million blocks wide, so the sum
|
||||
// at the far edge of the world overflows an i32.
|
||||
let (ox64, oz64, size64) = (i64::from(ox), i64::from(oz), i64::from(size));
|
||||
if (ox64..ox64 + size64).contains(&i64::from(camera[0]))
|
||||
&& (oz64..oz64 + size64).contains(&i64::from(camera[1]))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
let half = f64::from(size) / 2.0;
|
||||
let cx = f64::from(ox) + half - f64::from(camera[0]);
|
||||
let cz = f64::from(oz) + half - f64::from(camera[1]);
|
||||
let distance = (cx * cx + cz * cz).sqrt();
|
||||
let radius = half * std::f64::consts::SQRT_2;
|
||||
if distance <= radius {
|
||||
return true;
|
||||
}
|
||||
let dir = [
|
||||
f64::from(self.dir[0]) / 1000.0,
|
||||
f64::from(self.dir[1]) / 1000.0,
|
||||
];
|
||||
let cos = (cx * dir[0] + cz * dir[1]) / distance;
|
||||
let sin = (1.0 - cos * cos).max(0.0).sqrt();
|
||||
// cos(angle - tile radius), expanded so no inverse trigonometry runs
|
||||
// per tile: the quadtree asks this of every node it visits.
|
||||
let radius_sin = (radius / distance).min(1.0);
|
||||
let radius_cos = (1.0 - radius_sin * radius_sin).max(0.0).sqrt();
|
||||
cos * radius_cos + sin * radius_sin >= f64::from(self.cos_half) / 1000.0
|
||||
}
|
||||
}
|
||||
|
||||
/// The coarsest tile level: `Plan` roots cover at most `MAX_CHUNKS` chunks
|
||||
/// around (a level-22 tile is 67 million blocks wide: the whole world).
|
||||
pub(crate) const MAX_LEVEL: u8 = 22;
|
||||
@@ -598,6 +702,8 @@ struct Plan {
|
||||
/// The squared distance within which planned tiles load before the
|
||||
/// coarse backdrop (`wanted_tiles`).
|
||||
first: i64,
|
||||
/// Where a zoomed view asks for finer tiles, if it does ([`ZoomAim`]).
|
||||
aim: Option<ZoomAim>,
|
||||
}
|
||||
/// Chunks past the render distance where only planned tiles are drawn (two
|
||||
/// past the last near chunk, `streaming::in_view_distance`), and where they
|
||||
@@ -607,7 +713,7 @@ const FIRST_CHUNKS: i32 = 4;
|
||||
impl Plan {
|
||||
#[cfg(test)]
|
||||
fn new(camera: [i32; 2], detail: i32, distance: u32) -> Self {
|
||||
Self::with_previous(camera, detail, distance, &Self::default(), 0, false)
|
||||
Self::with_previous(camera, detail, distance, &Self::default(), 0, false, None)
|
||||
}
|
||||
/// `reduced`: Reduced far detail (`graphics::FarDetail`), each level from
|
||||
/// half the distance.
|
||||
@@ -618,6 +724,7 @@ impl Plan {
|
||||
previous: &Self,
|
||||
elevation: i32,
|
||||
reduced: bool,
|
||||
aim: Option<ZoomAim>,
|
||||
) -> Self {
|
||||
let range = distance.min(MAX_CHUNKS) as i32 * 16;
|
||||
let mut level = 0;
|
||||
@@ -630,6 +737,7 @@ impl Plan {
|
||||
camera,
|
||||
near: i64::from((detail + SEAM_CHUNKS) * 16).pow(2),
|
||||
first: i64::from((detail + FIRST_CHUNKS) * 16).pow(2),
|
||||
aim,
|
||||
..Self::default()
|
||||
};
|
||||
for z in (camera[1] - range).div_euclid(size)..=(camera[1] + range).div_euclid(size) {
|
||||
@@ -665,6 +773,14 @@ impl Plan {
|
||||
// Beyond the old 1024-chunk limit the cells are as large as `reduced`'s:
|
||||
// the whole world is 22 levels, not all of them worth full cells.
|
||||
let world = key.distance(camera) >= WORLD_START;
|
||||
// A zoomed view magnifies the tiles its cone covers, so those split
|
||||
// further; every other tile keeps the plan it would have had
|
||||
// ([`ZoomAim`]). The world-wide threshold is boosted too: the horizon is
|
||||
// where a spyglass shows the coarsest cells of all.
|
||||
let boost = match self.aim {
|
||||
Some(aim) if aim.covers(key, camera) => i64::from(aim.boost),
|
||||
_ => 1,
|
||||
};
|
||||
let threshold = i64::from(key.size())
|
||||
* i64::from(if world {
|
||||
WORLD_SPLIT
|
||||
@@ -672,7 +788,8 @@ impl Plan {
|
||||
split / 2
|
||||
} else {
|
||||
split
|
||||
});
|
||||
})
|
||||
* boost;
|
||||
// The 8 to 10 band above is wide already. The ring of full detail
|
||||
// around the camera and the world-wide threshold have none: a tile
|
||||
// split last plan stays split until it is 5% past them, or it
|
||||
@@ -875,7 +992,16 @@ struct MeshInput {
|
||||
}
|
||||
struct ReducedColumns {
|
||||
columns: Arc<[Column; 256]>,
|
||||
levels: [Vec<Column>; 4],
|
||||
/// The chunk reduced to cells 2, 4, 8 and 16 blocks wide, each built the
|
||||
/// first time a tile of that width asks for it.
|
||||
///
|
||||
/// One chunk is covered by one far tile, so one of the four is what gets
|
||||
/// read, and a chunk whose detail arrives while full-detail terrain still
|
||||
/// draws it reads none. Building all four up front cost 405 us of a far
|
||||
/// terrain thread for every chunk the world sent (`Column::reduced` walks
|
||||
/// every span of the footprint four times over), and held 85 columns
|
||||
/// beside the chunk's 256.
|
||||
levels: [std::sync::OnceLock<Vec<Column>>; 4],
|
||||
}
|
||||
impl MeshInput {
|
||||
/// The column of every cell: the tile's own samples unless the snapshot
|
||||
@@ -905,25 +1031,26 @@ impl MeshInput {
|
||||
}
|
||||
impl ReducedColumns {
|
||||
fn new(columns: Arc<[Column; 256]>) -> Self {
|
||||
let levels = std::array::from_fn(|level| {
|
||||
let width = 2 << level;
|
||||
Self {
|
||||
columns,
|
||||
levels: std::array::from_fn(|_| std::sync::OnceLock::new()),
|
||||
}
|
||||
}
|
||||
fn get(&self, x: usize, z: usize, width: usize) -> &Column {
|
||||
if width == 1 {
|
||||
return &self.columns[z * 16 + x];
|
||||
}
|
||||
let level = width.trailing_zeros() as usize - 1;
|
||||
let reduced = self.levels[level].get_or_init(|| {
|
||||
let columns = &self.columns;
|
||||
(0..16 / width)
|
||||
.flat_map(|z| {
|
||||
let columns = &columns;
|
||||
(0..16 / width)
|
||||
.map(move |x| Column::reduced(columns, x * width, z * width, width))
|
||||
})
|
||||
.collect()
|
||||
});
|
||||
Self { columns, levels }
|
||||
}
|
||||
fn get(&self, x: usize, z: usize, width: usize) -> &Column {
|
||||
if width == 1 {
|
||||
&self.columns[z * 16 + x]
|
||||
} else {
|
||||
&self.levels[width.trailing_zeros() as usize - 1]
|
||||
[(z / width) * (16 / width) + x / width]
|
||||
}
|
||||
&reduced[(z / width) * (16 / width) + x / width]
|
||||
}
|
||||
}
|
||||
enum Job {
|
||||
@@ -1049,7 +1176,7 @@ pub struct Lod {
|
||||
context: Option<Arc<WorkerContext>>,
|
||||
/// A finished mesh job may have changed the selection of its ancestors.
|
||||
reselect: bool,
|
||||
area: Option<([i32; 2], i32, u32, i32, bool)>,
|
||||
area: Option<([i32; 2], i32, u32, i32, bool, Option<ZoomAim>)>,
|
||||
plan: Plan,
|
||||
/// Reduced far detail (`set_reduced_detail`).
|
||||
reduced_detail: bool,
|
||||
@@ -2210,29 +2337,35 @@ impl Lod {
|
||||
self.shared.wake.notify_all();
|
||||
}
|
||||
}
|
||||
/// `aim` asks the tiles a zoomed view magnifies for finer detail
|
||||
/// ([`ZoomAim`]); `None` plans exactly as before.
|
||||
pub fn update(
|
||||
&mut self,
|
||||
camera: [f64; 3],
|
||||
detail: i32,
|
||||
distance: u32,
|
||||
covered: Option<FxHashSet<(i32, i32)>>,
|
||||
aim: Option<ZoomAim>,
|
||||
) -> Vec<(TileKey, SectionMesh)> {
|
||||
let elevation =
|
||||
(((camera[1] - f64::from(MIN_Y + crate::chunk::HEIGHT)).clamp(0., 16384.)) as i32 / 32)
|
||||
* 32;
|
||||
let camera = [camera[0].floor() as i32, camera[2].floor() as i32];
|
||||
// Replan at chunk boundaries, not on every camera movement.
|
||||
// `ZoomAim` rounds its yaw, so a zoom held still keeps one area and the
|
||||
// quadtree is not rebuilt as the player nudges the mouse.
|
||||
let area = (
|
||||
[camera[0].div_euclid(16), camera[1].div_euclid(16)],
|
||||
detail,
|
||||
distance,
|
||||
elevation,
|
||||
self.reduced_detail,
|
||||
aim,
|
||||
);
|
||||
if self.area != Some(area) {
|
||||
crate::spans::time("lod_plan", || {
|
||||
self.area = Some(area);
|
||||
self.replan(camera, detail, distance, elevation);
|
||||
self.replan(camera, detail, distance, elevation, aim);
|
||||
});
|
||||
}
|
||||
let mut meshes = Vec::new();
|
||||
@@ -2255,7 +2388,14 @@ impl Lod {
|
||||
}
|
||||
/// Rebuilds the quadtree and the selection it implies. Only runs when the
|
||||
/// planned area changes (a chunk boundary), never per finished sample.
|
||||
fn replan(&mut self, camera: [i32; 2], detail: i32, distance: u32, elevation: i32) {
|
||||
fn replan(
|
||||
&mut self,
|
||||
camera: [i32; 2],
|
||||
detail: i32,
|
||||
distance: u32,
|
||||
elevation: i32,
|
||||
aim: Option<ZoomAim>,
|
||||
) {
|
||||
let plan = Plan::with_previous(
|
||||
camera,
|
||||
detail,
|
||||
@@ -2263,6 +2403,7 @@ impl Lod {
|
||||
&self.plan,
|
||||
elevation,
|
||||
self.reduced_detail,
|
||||
aim,
|
||||
);
|
||||
// A tile that leaves the range before it was drawn stops being
|
||||
// unknown to its neighbours (`Snapshot::planned_leaf`): they remesh
|
||||
@@ -2952,6 +3093,104 @@ fn retiring_detail<'a>(
|
||||
}
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
/// A spyglass or the zoom mod magnifies only what the narrowed view
|
||||
/// covers, so `ZoomAim` asks for finer tiles there and nowhere else. Without
|
||||
/// that cone the same request would reach the whole circle, which at the
|
||||
/// measured quads a tile is gigabytes of vertices.
|
||||
#[test]
|
||||
fn a_zoomed_view_asks_for_finer_tiles_only_where_it_looks() {
|
||||
// Yaw 0 looks toward +z (`view_vector`), ten times magnified.
|
||||
let aim = ZoomAim::new(0.0, 7.0, 10.0).expect("a tenth of the field of view zooms");
|
||||
// Capped, however far the zoom goes.
|
||||
assert_eq!(aim.boost, MAX_ZOOM_BOOST);
|
||||
let camera = [0, 0];
|
||||
let tile = |x, z, level| TileKey { x, z, level };
|
||||
// Straight ahead, far enough that the direction decides it.
|
||||
assert!(aim.covers(tile(0, 8, 4), camera), "ahead");
|
||||
// Behind, beside, and the opposite diagonal: the zoom does not
|
||||
// magnify these, so they keep the plan they would have had.
|
||||
assert!(!aim.covers(tile(0, -9, 4), camera), "behind");
|
||||
assert!(!aim.covers(tile(8, 0, 4), camera), "beside");
|
||||
assert!(!aim.covers(tile(-9, -9, 4), camera), "diagonally behind");
|
||||
// A tile the camera stands in is in view whichever way it faces.
|
||||
assert!(aim.covers(tile(0, 0, 4), camera), "underfoot");
|
||||
}
|
||||
|
||||
/// A zoom too slight to change which level a tile wants is not worth
|
||||
/// rebuilding the quadtree for, and an unzoomed view must plan exactly as
|
||||
/// it did before this feature.
|
||||
#[test]
|
||||
fn a_slight_zoom_does_not_replan() {
|
||||
assert_eq!(ZoomAim::new(0.0, 70.0, 1.0), None, "not zoomed");
|
||||
assert_eq!(
|
||||
ZoomAim::new(0.0, 60.0, 1.2),
|
||||
None,
|
||||
"a fifth is under one level"
|
||||
);
|
||||
assert!(ZoomAim::new(0.0, 35.0, 2.0).is_some(), "twice is worth it");
|
||||
// Nothing finite comes of a broken field of view.
|
||||
assert_eq!(ZoomAim::new(0.0, f32::NAN, 4.0), None);
|
||||
assert_eq!(ZoomAim::new(0.0, 0.0, 4.0), None);
|
||||
assert_eq!(ZoomAim::new(0.0, 70.0, f32::INFINITY), None);
|
||||
}
|
||||
|
||||
/// The cone turns with the player, and its yaw is rounded so that a
|
||||
/// mouse-twitch does not rebuild the quadtree: two aims within the
|
||||
/// rounding step compare equal, and `Lod::update` replans on that.
|
||||
#[test]
|
||||
fn the_cone_turns_and_rounds_with_the_view() {
|
||||
let camera = [0, 0];
|
||||
let east = ZoomAim::new(-90.0, 7.0, 10.0).expect("zoomed");
|
||||
let tile = |x, z| TileKey { x, z, level: 4 };
|
||||
// Yaw -90 looks toward +x.
|
||||
assert!(east.covers(tile(8, 0), camera), "ahead when facing +x");
|
||||
assert!(!east.covers(tile(0, 8), camera), "+z is no longer ahead");
|
||||
// Within the rounding step: the same aim, so no replan.
|
||||
assert_eq!(ZoomAim::new(0.0, 7.0, 10.0), ZoomAim::new(1.0, 7.0, 10.0));
|
||||
// Past it: a different aim, so the cone follows.
|
||||
assert_ne!(ZoomAim::new(0.0, 7.0, 10.0), ZoomAim::new(20.0, 7.0, 10.0));
|
||||
}
|
||||
|
||||
/// Inside the cone a tile splits further than it would unzoomed, and
|
||||
/// outside it the plan is unchanged, tile for tile.
|
||||
#[test]
|
||||
fn the_plan_is_finer_ahead_and_untouched_behind() {
|
||||
let camera = [0, 0];
|
||||
let plain = Plan::with_previous(camera, 12, 256, &Plan::default(), 0, false, None);
|
||||
let zoomed = Plan::with_previous(
|
||||
camera,
|
||||
12,
|
||||
256,
|
||||
&Plan::default(),
|
||||
0,
|
||||
false,
|
||||
ZoomAim::new(0.0, 7.0, 10.0),
|
||||
);
|
||||
// Finer somewhere: the zoomed plan holds tiles the plain one split
|
||||
// no further.
|
||||
assert!(
|
||||
zoomed.nodes.len() > plain.nodes.len(),
|
||||
"zoomed {} tiles, plain {}",
|
||||
zoomed.nodes.len(),
|
||||
plain.nodes.len()
|
||||
);
|
||||
// Behind the camera the two agree. Tiles there are the same level in
|
||||
// both, so every plain node well behind is still a node when zoomed.
|
||||
let behind = |key: &&TileKey| {
|
||||
let [_, _, oz] = key.origin();
|
||||
oz + key.size() < -1024
|
||||
};
|
||||
let plain_behind: std::collections::BTreeSet<_> =
|
||||
plain.nodes.iter().filter(behind).copied().collect();
|
||||
let zoomed_behind: std::collections::BTreeSet<_> =
|
||||
zoomed.nodes.iter().filter(behind).copied().collect();
|
||||
assert!(!plain_behind.is_empty(), "nothing behind to compare");
|
||||
assert_eq!(
|
||||
plain_behind, zoomed_behind,
|
||||
"the zoom changed the plan behind the player"
|
||||
);
|
||||
}
|
||||
|
||||
use super::*;
|
||||
use crate::mesher::TerrainVertex;
|
||||
#[test]
|
||||
@@ -3023,7 +3262,8 @@ mod tests {
|
||||
for camera in [[0, 0], [100, -40]] {
|
||||
for distance in [64, 128, 512, 1024] {
|
||||
let full = Plan::new(camera, 12, distance);
|
||||
let reduced = Plan::with_previous(camera, 12, distance, &Plan::default(), 0, true);
|
||||
let reduced =
|
||||
Plan::with_previous(camera, 12, distance, &Plan::default(), 0, true, None);
|
||||
// Never finer than Full anywhere, and as fine next to the
|
||||
// full-detail area, whose edge the finest tiles match.
|
||||
assert!(reduced.split.is_subset(&full.split));
|
||||
@@ -3083,10 +3323,24 @@ mod tests {
|
||||
([115, 135], 49_000_000),
|
||||
([-30_000_000, 29_999_000], 90),
|
||||
] {
|
||||
let plan =
|
||||
Plan::with_previous(camera, 12, MAX_CHUNKS, &Plan::default(), elevation, false);
|
||||
let reduced =
|
||||
Plan::with_previous(camera, 12, MAX_CHUNKS, &Plan::default(), elevation, true);
|
||||
let plan = Plan::with_previous(
|
||||
camera,
|
||||
12,
|
||||
MAX_CHUNKS,
|
||||
&Plan::default(),
|
||||
elevation,
|
||||
false,
|
||||
None,
|
||||
);
|
||||
let reduced = Plan::with_previous(
|
||||
camera,
|
||||
12,
|
||||
MAX_CHUNKS,
|
||||
&Plan::default(),
|
||||
elevation,
|
||||
true,
|
||||
None,
|
||||
);
|
||||
let top = plan.nodes.iter().map(|k| k.level).max().unwrap();
|
||||
assert_eq!(top, MAX_LEVEL, "{camera:?} y={elevation}: roots stop short");
|
||||
assert!(
|
||||
@@ -3113,7 +3367,7 @@ mod tests {
|
||||
#[test]
|
||||
fn aerial_distance_avoids_unseen_full_detail_outside_the_near_area() {
|
||||
let ground = Plan::new([0, 0], 12, 1024);
|
||||
let high = Plan::with_previous([0, 0], 12, 1024, &Plan::default(), 1024, false);
|
||||
let high = Plan::with_previous([0, 0], 12, 1024, &Plan::default(), 1024, false, None);
|
||||
assert!(high.nodes.len() < ground.nodes.len());
|
||||
assert!(
|
||||
high.nodes.contains(&TileKey {
|
||||
@@ -3168,7 +3422,7 @@ mod tests {
|
||||
// stand-in for a covered column, and only the roots are sampled.
|
||||
let camera = [8, 8];
|
||||
let before = Plan::new(camera, 64, 64);
|
||||
let after = Plan::with_previous(camera, 8, 64, &before, 0, false);
|
||||
let after = Plan::with_previous(camera, 8, 64, &before, 0, false, None);
|
||||
let mut ready: FxHashMap<TileKey, ()> = before
|
||||
.nodes
|
||||
.iter()
|
||||
@@ -3207,7 +3461,7 @@ mod tests {
|
||||
#[test]
|
||||
fn detail_survives_movement_across_a_split_threshold() {
|
||||
let before = Plan::new([0, 0], 2, 256);
|
||||
let after = Plan::with_previous([16, 0], 2, 256, &before, 0, false);
|
||||
let after = Plan::with_previous([16, 0], 2, 256, &before, 0, false, None);
|
||||
let mut retained = 0;
|
||||
let range = i64::from(256 * 16);
|
||||
for key in &before.split {
|
||||
@@ -3232,12 +3486,12 @@ mod tests {
|
||||
let before = Plan::new([0, 0], 40, 256);
|
||||
assert!(before.split.contains(&tile));
|
||||
// 670 blocks: past the ring, inside 5% of it.
|
||||
let held = Plan::with_previous([-30, 0], 40, 256, &before, 0, false);
|
||||
let held = Plan::with_previous([-30, 0], 40, 256, &before, 0, false, None);
|
||||
assert!(held.split.contains(&tile));
|
||||
// Not held without having been split: it was never in the ring.
|
||||
assert!(!Plan::new([-30, 0], 40, 256).split.contains(&tile));
|
||||
// 700 blocks: past the margin.
|
||||
let gone = Plan::with_previous([-60, 0], 40, 256, &before, 0, false);
|
||||
let gone = Plan::with_previous([-60, 0], 40, 256, &before, 0, false, None);
|
||||
assert!(!gone.split.contains(&tile));
|
||||
}
|
||||
#[test]
|
||||
@@ -3348,6 +3602,44 @@ mod tests {
|
||||
"a crown over one corner of a wide cell still sits on its trunk"
|
||||
);
|
||||
}
|
||||
/// A chunk is reduced to the one cell width that reads it, when it does.
|
||||
///
|
||||
/// Reducing to all four widths up front cost 405 us of a far terrain
|
||||
/// thread for every chunk the world sent, where at most one is read.
|
||||
#[test]
|
||||
fn a_chunk_is_reduced_only_to_the_width_that_reads_it() {
|
||||
let built = |reduced: &ReducedColumns| {
|
||||
reduced
|
||||
.levels
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|(_, level)| level.get().is_some())
|
||||
.map(|(level, _)| 2usize << level)
|
||||
.collect::<Vec<_>>()
|
||||
};
|
||||
let reduced = ReducedColumns::new(Arc::new(std::array::from_fn(|i| Column {
|
||||
surface: None,
|
||||
spans: vec![Span {
|
||||
min: 0,
|
||||
max: 4 + (i % 3) as i16,
|
||||
state: BlockStateId(1),
|
||||
biome: 0,
|
||||
light: 240,
|
||||
}]
|
||||
.into(),
|
||||
})));
|
||||
assert!(built(&reduced).is_empty(), "nothing is reduced unread");
|
||||
// A tile of full-detail cells reads the chunk's own columns.
|
||||
reduced.get(3, 5, 1);
|
||||
assert!(built(&reduced).is_empty());
|
||||
reduced.get(4, 8, 4);
|
||||
assert_eq!(built(&reduced), [4]);
|
||||
// Read again, and the reduction is the one already built.
|
||||
reduced.get(0, 0, 4);
|
||||
assert_eq!(built(&reduced), [4]);
|
||||
reduced.get(0, 0, 16);
|
||||
assert_eq!(built(&reduced), [4, 16]);
|
||||
}
|
||||
/// Detail read before a refresh over its chunk is dropped (asked
|
||||
/// again); elsewhere, or read after, it is kept.
|
||||
#[test]
|
||||
@@ -3701,7 +3993,7 @@ mod tests {
|
||||
// Exercise the actual worker/update seam: a parent stays displayed
|
||||
// until all four child meshes can replace it in the same update.
|
||||
let camera = [-256.0, 100.0, -256.0];
|
||||
lod.area = Some(([-16, -16], 2, 64, 0, false));
|
||||
lod.area = Some(([-16, -16], 2, 64, 0, false, None));
|
||||
lod.plan.roots = vec![key];
|
||||
lod.plan.nodes.insert(key);
|
||||
// As a replan does (`update` only selects after a change).
|
||||
@@ -3709,7 +4001,7 @@ mod tests {
|
||||
let await_meshes = |lod: &mut Lod| {
|
||||
let deadline = std::time::Instant::now() + std::time::Duration::from_secs(5);
|
||||
loop {
|
||||
let meshes = lod.update(camera, 2, 64, None);
|
||||
let meshes = lod.update(camera, 2, 64, None, None);
|
||||
if !meshes.is_empty() {
|
||||
return meshes;
|
||||
}
|
||||
@@ -3727,7 +4019,7 @@ mod tests {
|
||||
lod.ready.insert(child, lod.ready[&key].clone());
|
||||
}
|
||||
lod.reselect = true;
|
||||
assert!(lod.update(camera, 2, 64, None).is_empty());
|
||||
assert!(lod.update(camera, 2, 64, None, None).is_empty());
|
||||
assert!(
|
||||
lod.active.contains(&key),
|
||||
"parent retired before child meshes"
|
||||
@@ -3756,7 +4048,7 @@ mod tests {
|
||||
lod.reselect = true;
|
||||
let deadline = std::time::Instant::now() + std::time::Duration::from_secs(5);
|
||||
loop {
|
||||
lod.update(camera, 2, 64, None);
|
||||
lod.update(camera, 2, 64, None, None);
|
||||
if lod.outstanding_meshes == 0 && lod.active.is_empty() {
|
||||
break;
|
||||
}
|
||||
@@ -3796,7 +4088,7 @@ mod tests {
|
||||
.collect();
|
||||
lod.detail_request_pending = true;
|
||||
lod.wanted_stale = true;
|
||||
lod.update(camera, 2, 64, Some(FxHashSet::default()));
|
||||
lod.update(camera, 2, 64, Some(FxHashSet::default()), None);
|
||||
let Some(Job::Sample(nearby)) = lod.shared.jobs.lock().unwrap().pop_front() else {
|
||||
panic!("nearby detail was not scheduled");
|
||||
};
|
||||
@@ -3807,7 +4099,7 @@ mod tests {
|
||||
"the nearest tiles load first"
|
||||
);
|
||||
lod.finish_sample(nearby, vec![Column::default(); 256]);
|
||||
lod.update(camera, 2, 64, Some(FxHashSet::default()));
|
||||
lod.update(camera, 2, 64, Some(FxHashSet::default()), None);
|
||||
let Some(Job::Sample(next)) = lod.shared.jobs.lock().unwrap().pop_front() else {
|
||||
panic!("the next ring was not scheduled");
|
||||
};
|
||||
@@ -3846,7 +4138,7 @@ mod tests {
|
||||
level: 0,
|
||||
})
|
||||
.collect();
|
||||
lod.update(camera, 2, 64, Some(FxHashSet::default()));
|
||||
lod.update(camera, 2, 64, Some(FxHashSet::default()), None);
|
||||
let Some(Job::Sample(first)) = lod.shared.jobs.lock().unwrap().pop_front() else {
|
||||
panic!("no final tile scheduled")
|
||||
};
|
||||
@@ -3890,7 +4182,7 @@ mod tests {
|
||||
lod.shared.jobs.lock().unwrap().clear();
|
||||
lod.pending.clear();
|
||||
lod.wanted_stale = true;
|
||||
lod.update([-256., 64., -256.], 2, 64, Some(FxHashSet::default()));
|
||||
lod.update([-256., 64., -256.], 2, 64, Some(FxHashSet::default()), None);
|
||||
let jobs = lod.shared.jobs.lock().unwrap();
|
||||
jobs.iter()
|
||||
.filter(|job| matches!(job, Job::Sample(_)))
|
||||
@@ -3906,7 +4198,7 @@ mod tests {
|
||||
// Leaves' cells: 1 block to 256 blocks out, 2 to 512 (Full); Reduced
|
||||
// keeps 1 to the near terrain's edge and 2 to 256.
|
||||
for (reduced, [one, two]) in [(false, [256, 512]), (true, [208, 256])] {
|
||||
let plan = Plan::with_previous([8, 8], 12, 128, &Plan::default(), 0, reduced);
|
||||
let plan = Plan::with_previous([8, 8], 12, 128, &Plan::default(), 0, reduced, None);
|
||||
for key in plan.nodes.iter().filter(|key| !plan.split.contains(key)) {
|
||||
let distance = key.distance([8, 8]);
|
||||
if distance < one {
|
||||
@@ -3936,7 +4228,8 @@ mod tests {
|
||||
}
|
||||
}
|
||||
}
|
||||
let plan = Plan::with_previous(camera, detail, distance, &Plan::default(), 0, reduced);
|
||||
let plan =
|
||||
Plan::with_previous(camera, detail, distance, &Plan::default(), 0, reduced, None);
|
||||
let leaf = |x: i32, z: i32| {
|
||||
(0..=MAX_LEVEL)
|
||||
.map(|level| TileKey {
|
||||
@@ -4202,7 +4495,7 @@ mod tests {
|
||||
lod.finish_sample(a, vec![Column::default(); CELLS * CELLS]);
|
||||
lod.dirty.clear();
|
||||
// A range of one chunk around (-10, 0) keeps `a` and drops `b`.
|
||||
lod.replan([-10, 0], 0, 1, 0);
|
||||
lod.replan([-10, 0], 0, 1, 0, None);
|
||||
assert!(lod.plan.nodes.contains(&a) && !lod.plan.nodes.contains(&b));
|
||||
assert!(lod.dirty.contains_key(&a), "its east wall is drawn now");
|
||||
}
|
||||
@@ -4257,7 +4550,7 @@ mod tests {
|
||||
keys
|
||||
};
|
||||
let none = || Some(FxHashSet::default());
|
||||
lod.update([8., 64., 8.], 2, 64, none());
|
||||
lod.update([8., 64., 8.], 2, 64, none(), None);
|
||||
let before = queued(&lod);
|
||||
assert_eq!(before.len(), 16, "a full queue once the near terrain is in");
|
||||
lod.shared
|
||||
@@ -4267,7 +4560,7 @@ mod tests {
|
||||
.push_back(Job::Observe((5, 5)));
|
||||
|
||||
// A chunk's move: the tiles still planned keep their place in line.
|
||||
lod.update([24., 64., 8.], 2, 64, none());
|
||||
lod.update([24., 64., 8.], 2, 64, none(), None);
|
||||
let moved = queued(&lod);
|
||||
let kept: Vec<_> = before
|
||||
.iter()
|
||||
@@ -4280,7 +4573,7 @@ mod tests {
|
||||
assert!(observing(&lod), "only sample jobs are dropped");
|
||||
|
||||
// A teleport: none of the old view's tiles is sampled any more.
|
||||
lod.update([100_000., 64., 100_000.], 2, 64, none());
|
||||
lod.update([100_000., 64., 100_000.], 2, 64, none(), None);
|
||||
let after = queued(&lod);
|
||||
assert_eq!(after.len(), 16);
|
||||
assert!(after.iter().all(|key| !moved.contains(key)));
|
||||
@@ -4298,7 +4591,7 @@ mod tests {
|
||||
assert!(lod.pending.is_empty());
|
||||
assert!(observing(&lod));
|
||||
lod.set_near_loading(false);
|
||||
lod.update([100_000., 64., 100_000.], 2, 64, none());
|
||||
lod.update([100_000., 64., 100_000.], 2, 64, none(), None);
|
||||
assert_eq!(queued(&lod), after);
|
||||
|
||||
// Larger machines keep the first `SAMPLE_JOBS` of the queue.
|
||||
@@ -4706,7 +4999,7 @@ mod tests {
|
||||
};
|
||||
for _ in 0..2 {
|
||||
for _ in 0..4000 {
|
||||
lod.update(camera, 2, 64, Some(FxHashSet::default()));
|
||||
lod.update(camera, 2, 64, Some(FxHashSet::default()), None);
|
||||
check(&lod);
|
||||
if !finish_queued(&mut lod) {
|
||||
break;
|
||||
@@ -4717,11 +5010,11 @@ mod tests {
|
||||
check(&lod);
|
||||
// Move a chunk: retained samples stay selected, new ones join.
|
||||
camera[0] += 16.0;
|
||||
lod.update(camera, 2, 64, Some(FxHashSet::default()));
|
||||
lod.update(camera, 2, 64, Some(FxHashSet::default()), None);
|
||||
check(&lod);
|
||||
}
|
||||
// A covered level-0 stand-in completes its parent but is not drawn.
|
||||
lod.update(camera, 2, 64, Some([(0, 0)].into_iter().collect()));
|
||||
lod.update(camera, 2, 64, Some([(0, 0)].into_iter().collect()), None);
|
||||
check(&lod);
|
||||
assert!(lod.ready.contains_key(&TileKey {
|
||||
x: 0,
|
||||
@@ -4734,7 +5027,7 @@ mod tests {
|
||||
level: 0
|
||||
}));
|
||||
// Shrinking the distance retires tiles and reports them once.
|
||||
lod.update(camera, 0, 32, Some(FxHashSet::default()));
|
||||
lod.update(camera, 0, 32, Some(FxHashSet::default()), None);
|
||||
check(&lod);
|
||||
let _ = lod.removed();
|
||||
}
|
||||
@@ -4818,7 +5111,7 @@ mod tests {
|
||||
let mut covered = Some(covered.clone());
|
||||
let mut quiet = 0;
|
||||
while quiet < if settle { 50 } else { 3 } {
|
||||
lod.update(camera, detail, distance, covered.take());
|
||||
lod.update(camera, detail, distance, covered.take(), None);
|
||||
lod.removed();
|
||||
// Every tile sampled, but those waiting for their data.
|
||||
let unsampled = lod.plan.nodes.iter().any(|key| {
|
||||
|
||||
@@ -1405,7 +1405,8 @@ fn pack_coords(coords: u32) -> u16 {
|
||||
pub struct Mesher<'a> {
|
||||
/// CardinalLighting.NETHER: brighter up/down faces.
|
||||
pub nether_shading: bool,
|
||||
/// A shader pack lights the faces (its `oldLighting` off): no face shading in the colours.
|
||||
/// A shader pack lights the faces (its `oldLighting` off): no face shading in the colours,
|
||||
/// only the dimension's up-face brightness (`lighting::pack_flat`).
|
||||
pub shader_pack_lighting: bool,
|
||||
/// OptiFine/Iris separate ambient occlusion: vertex RGB does not include AO, and AO factor is passed in vertex alpha.
|
||||
pub separate_ao: bool,
|
||||
@@ -1660,8 +1661,10 @@ impl Mesher<'_> {
|
||||
None => ao,
|
||||
};
|
||||
let shade_face = q.shade_direction_override.unwrap_or(q.facing);
|
||||
let directional = if self.shader_pack_lighting || !q.shade {
|
||||
let directional = if !q.shade {
|
||||
1.0
|
||||
} else if self.shader_pack_lighting {
|
||||
lighting::pack_flat(self.nether_shading)
|
||||
} else {
|
||||
lighting::cardinal(self.nether_shading, shade_face)
|
||||
};
|
||||
|
||||
@@ -189,8 +189,9 @@ impl FluidFlowWorld for FlowView<'_> {
|
||||
}
|
||||
}
|
||||
/// Emits one fluid cell at section-relative `[x, y, z]`.
|
||||
/// `(nether, shader_pack_lighting, separate_ao)`: the Nether's face shading, none when a shader pack
|
||||
/// lights the faces (`Mesher::shader_pack_lighting`), and whether to keep pure alpha for separate AO.
|
||||
/// `(nether, shader_pack_lighting, separate_ao)`: the Nether's face shading, only the up-face value
|
||||
/// when a shader pack lights the faces (`Mesher::shader_pack_lighting`), and whether to keep pure
|
||||
/// alpha for separate AO.
|
||||
pub(super) fn tesselate(
|
||||
tables: &MeshTables,
|
||||
(nether, shader_pack_lighting, separate_ao): (bool, bool, bool),
|
||||
@@ -202,7 +203,7 @@ pub(super) fn tesselate(
|
||||
use horizon_assets::model::Direction as D;
|
||||
let cardinal = |d: D| {
|
||||
if shader_pack_lighting {
|
||||
1.0
|
||||
lighting::pack_flat(nether)
|
||||
} else {
|
||||
lighting::cardinal(nether, d)
|
||||
}
|
||||
@@ -447,7 +448,10 @@ pub(super) fn tesselate(
|
||||
Some(layer) if face_state.overlay => (layer, true),
|
||||
_ => (flow, false),
|
||||
};
|
||||
let side = if matches!(d, Direction::North | Direction::South) {
|
||||
// Vanilla's side is the up value times the side's; a shader pack's has no side factor.
|
||||
let side = if shader_pack_lighting {
|
||||
1.0
|
||||
} else if matches!(d, Direction::North | Direction::South) {
|
||||
cardinal(D::North)
|
||||
} else {
|
||||
cardinal(D::West)
|
||||
|
||||
@@ -19,6 +19,12 @@ pub(super) fn cardinal(nether: bool, face: D) -> f32 {
|
||||
D::West | D::East => 0.6,
|
||||
}
|
||||
}
|
||||
/// A face's brightness when a shader pack lights the faces (`Mesher::shader_pack_lighting`): no
|
||||
/// directional shading, every face at the dimension's up-face value (1.0, the Nether's 0.9).
|
||||
/// Our probe pack's Iris 1.11.7 values fit this: 0.9 on every Nether face, 1.0 in the overworld.
|
||||
pub(super) fn pack_flat(nether: bool) -> f32 {
|
||||
cardinal(nether, D::Up)
|
||||
}
|
||||
fn normal(face: D) -> [i32; 3] {
|
||||
match face {
|
||||
D::Down => [0, -1, 0],
|
||||
|
||||
@@ -159,6 +159,60 @@ fn a_shader_pack_lights_the_faces_itself() {
|
||||
assert_eq!(colours(true).len(), 1);
|
||||
}
|
||||
|
||||
/// Run explicitly with prepared assets. With a shader pack lighting the faces, every face of a
|
||||
/// block and of a lava source takes the dimension's up-face brightness, as Iris 1.11.7 gives our
|
||||
/// probe pack: 0.9 in the Nether (`CardinalLighting.NETHER`'s up, 229 of 255), 1.0 elsewhere.
|
||||
#[test]
|
||||
#[ignore = "requires prepared 26.3 resources (HORIZON_MESH_TEST_RESOURCES or .local/horizon-client/26.3)"]
|
||||
fn a_shader_pack_lights_every_nether_face_like_an_up_face() {
|
||||
let root = std::env::var_os("HORIZON_MESH_TEST_RESOURCES")
|
||||
.map(std::path::PathBuf::from)
|
||||
.unwrap_or_else(|| {
|
||||
std::path::Path::new(env!("CARGO_MANIFEST_DIR"))
|
||||
.join("../../.local/horizon-client/26.3")
|
||||
});
|
||||
let assets = Assets::load(&root).unwrap();
|
||||
let facts = BlockFacts::load(&root, assets.registry).unwrap();
|
||||
let biomes = Biomes::load(&root).unwrap();
|
||||
let render = assets.reload(&root).unwrap();
|
||||
let visibility = crate::models::load_visibility(&root, assets.registry).unwrap();
|
||||
let tables = MeshTables::new(&assets, &render, &facts, visibility.clone()).unwrap();
|
||||
let state = |name| assets.registry.default_state(name).unwrap().0;
|
||||
let mut chunk = Chunk::empty(0, 0);
|
||||
chunk.set(4, MIN_Y + 8, 4, state("minecraft:netherrack"));
|
||||
chunk.set(11, MIN_Y + 8, 11, state("minecraft:lava"));
|
||||
let mut region = [[None; 3]; 3];
|
||||
region[1][1] = Some(&chunk);
|
||||
let colours = |nether_shading| {
|
||||
let mut mesher = Mesher {
|
||||
nether_shading,
|
||||
shader_pack_lighting: true,
|
||||
separate_ao: false,
|
||||
assets: &assets,
|
||||
render: &render,
|
||||
tables: &tables,
|
||||
biomes: &biomes,
|
||||
visibility: visibility.clone(),
|
||||
zoom: BiomeZoom::new(0),
|
||||
blend_radius: 0,
|
||||
smooth_lighting: false,
|
||||
cutout_leaves: true,
|
||||
translucent_layers: &[],
|
||||
leaf_culling: LeafCullingMode::Off,
|
||||
};
|
||||
let mesh = mesher.mesh(®ion, 0);
|
||||
// Both blocks' six faces: 2 × 6 quads of 4 vertices.
|
||||
let all: Vec<_> = mesh.solid.iter().chain(&mesh.translucent).collect();
|
||||
assert!(all.len() >= 48, "{} vertices", all.len());
|
||||
let mut colours: Vec<u32> = all.iter().map(|v| v.color & 0xFF_FFFF).collect();
|
||||
colours.sort_unstable();
|
||||
colours.dedup();
|
||||
colours
|
||||
};
|
||||
assert_eq!(colours(true), [0xE5_E5E5]);
|
||||
assert_eq!(colours(false), [0xFF_FFFF]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore = "requires prepared 26.3 resources (HORIZON_MESH_TEST_RESOURCES or .local/horizon-client/26.3)"]
|
||||
fn separate_ao_passes_ao_in_alpha_without_darkening_rgb() {
|
||||
|
||||
@@ -263,9 +263,6 @@ static TABLE: LazyLock<Vec<Def>> = LazyLock::new(|| {
|
||||
for part in MODEL_PARTS {
|
||||
t.push(pb(&format!("modelPart_{part}"), true));
|
||||
}
|
||||
// Horizon's own: the outer skin layer drawn as slabs (Options → Skin
|
||||
// Customization), read by the renderer when a skin is resolved.
|
||||
t.push(pb("threeDSkinLayers", false));
|
||||
t
|
||||
});
|
||||
|
||||
|
||||
@@ -272,13 +272,16 @@ impl Opt {
|
||||
Opt::PadAdaptiveTriggers => "horizon.options.adaptive_triggers",
|
||||
Opt::PadLightbar => "horizon.options.lightbar",
|
||||
Opt::PadLookSensitivity => "horizon.options.look_sensitivity",
|
||||
Opt::PadPointerSpeed => "horizon.options.pointer_speed",
|
||||
Opt::PadScrollSpeed => "horizon.options.scroll_speed",
|
||||
Opt::PadRepeatDelay => "horizon.options.repeat_delay",
|
||||
Opt::PadRepeatInterval => "horizon.options.repeat_interval",
|
||||
Opt::PadInvertX => "horizon.options.invert_x",
|
||||
Opt::PadInvertY => "horizon.options.invert_y",
|
||||
Opt::PadToggleSneak => "horizon.options.sneak_button",
|
||||
Opt::PadMoveDeadzone => "horizon.options.move_deadzone",
|
||||
Opt::PadLookDeadzone => "horizon.options.look_deadzone",
|
||||
Opt::PadGlyphs => "horizon.options.button_glyphs",
|
||||
Opt::PadMenuNav => "horizon.options.menu_navigation",
|
||||
Opt::PadKeyboard => "horizon.options.on_screen_keyboard",
|
||||
Opt::ModelPart(i) => [
|
||||
"options.modelPart.cape",
|
||||
@@ -352,6 +355,10 @@ impl Opt {
|
||||
Opt::ChatHeightUnfocused => Kind::Slider(s.chat_height_unfocused),
|
||||
Opt::ChatLineSpacing => Kind::Slider(s.chat_line_spacing),
|
||||
Opt::PadLookSensitivity => Kind::Slider(s.controller.look_sensitivity),
|
||||
Opt::PadPointerSpeed => unit(s.controller.pointer_speed, 0.25, 3.0),
|
||||
Opt::PadScrollSpeed => unit(s.controller.scroll_speed, 1.0, 36.0),
|
||||
Opt::PadRepeatDelay => unit(s.controller.repeat_delay, 0.1, 1.0),
|
||||
Opt::PadRepeatInterval => unit(s.controller.repeat_interval, 0.03, 0.3),
|
||||
Opt::PadMoveDeadzone => unit(s.controller.move_deadzone, 0.0, 0.5),
|
||||
Opt::PadLookDeadzone => unit(s.controller.look_deadzone, 0.0, 0.5),
|
||||
Opt::SprintWindow => unit(s.sprint_window as f32, 0.0, 10.0),
|
||||
@@ -610,6 +617,23 @@ impl Opt {
|
||||
),
|
||||
),
|
||||
Opt::PadLookSensitivity => percent(c, 2.0 * s.controller.look_sensitivity),
|
||||
Opt::PadPointerSpeed => percent(c, s.controller.pointer_speed),
|
||||
Opt::PadScrollSpeed => percent(c, s.controller.scroll_speed / 12.0),
|
||||
Opt::PadRepeatDelay | Opt::PadRepeatInterval => generic(
|
||||
c,
|
||||
Text::tr(
|
||||
"horizon.options.milliseconds",
|
||||
&[&format!(
|
||||
"{:.0}",
|
||||
1000.0
|
||||
* if self == Opt::PadRepeatDelay {
|
||||
s.controller.repeat_delay
|
||||
} else {
|
||||
s.controller.repeat_interval
|
||||
}
|
||||
)],
|
||||
),
|
||||
),
|
||||
Opt::PadMoveDeadzone | Opt::PadLookDeadzone => {
|
||||
let v = if self == Opt::PadMoveDeadzone {
|
||||
s.controller.move_deadzone
|
||||
@@ -730,7 +754,7 @@ impl Opt {
|
||||
} else {
|
||||
"options.key.hold"
|
||||
}),
|
||||
Opt::SkinLayers3d => tr(if s.three_d_skin_layers {
|
||||
Opt::SkinLayers3d => tr(if s.extras.three_d_skin_layers {
|
||||
"options.on"
|
||||
} else {
|
||||
"options.off"
|
||||
@@ -796,10 +820,6 @@ impl Opt {
|
||||
GlyphStyle::PlayStation => "horizon.options.glyphs.playstation",
|
||||
GlyphStyle::Nintendo => "horizon.options.glyphs.nintendo",
|
||||
}),
|
||||
Opt::PadMenuNav => tr(match s.controller.menu_nav {
|
||||
gamepad::MenuNav::Focus => "horizon.options.menu_focus",
|
||||
gamepad::MenuNav::Pointer => "horizon.options.menu_pointer",
|
||||
}),
|
||||
Opt::PadKeyboard => tr(match s.controller.keyboard {
|
||||
gamepad::TextKeyboard::Auto => "horizon.options.keyboard.auto",
|
||||
gamepad::TextKeyboard::Horizon => "horizon.options.keyboard.horizon",
|
||||
@@ -871,6 +891,10 @@ impl Opt {
|
||||
Opt::ChatHeightUnfocused => s.chat_height_unfocused = v,
|
||||
Opt::ChatLineSpacing => s.chat_line_spacing = v,
|
||||
Opt::PadLookSensitivity => s.controller.look_sensitivity = v,
|
||||
Opt::PadPointerSpeed => s.controller.pointer_speed = step(25.0, 300.0) / 100.0,
|
||||
Opt::PadScrollSpeed => s.controller.scroll_speed = step(1.0, 36.0),
|
||||
Opt::PadRepeatDelay => s.controller.repeat_delay = step(100.0, 1000.0) / 1000.0,
|
||||
Opt::PadRepeatInterval => s.controller.repeat_interval = step(30.0, 300.0) / 1000.0,
|
||||
Opt::PadMoveDeadzone => s.controller.move_deadzone = step(0.0, 50.0) / 100.0,
|
||||
Opt::PadLookDeadzone => s.controller.look_deadzone = step(0.0, 50.0) / 100.0,
|
||||
Opt::SprintWindow => s.sprint_window = step(0.0, 10.0) as i32,
|
||||
@@ -1019,7 +1043,7 @@ impl Opt {
|
||||
Opt::ChunkBuilder => s.prioritize_chunk_updates = next(s.prioritize_chunk_updates, 3),
|
||||
Opt::ToggleCrouch => s.toggle_crouch = !s.toggle_crouch,
|
||||
Opt::ToggleSprint => s.toggle_sprint = !s.toggle_sprint,
|
||||
Opt::SkinLayers3d => s.three_d_skin_layers = !s.three_d_skin_layers,
|
||||
Opt::SkinLayers3d => s.extras.three_d_skin_layers = !s.extras.three_d_skin_layers,
|
||||
Opt::ToggleAttack => s.toggle_attack = !s.toggle_attack,
|
||||
Opt::ToggleUse => s.toggle_use = !s.toggle_use,
|
||||
Opt::AutoJump => s.auto_jump = !s.auto_jump,
|
||||
@@ -1094,12 +1118,6 @@ impl Opt {
|
||||
.unwrap_or(0) as u8;
|
||||
s.controller.glyphs = GlyphStyle::ALL[usize::from(next(i, 4))];
|
||||
}
|
||||
Opt::PadMenuNav => {
|
||||
s.controller.menu_nav = match s.controller.menu_nav {
|
||||
gamepad::MenuNav::Focus => gamepad::MenuNav::Pointer,
|
||||
gamepad::MenuNav::Pointer => gamepad::MenuNav::Focus,
|
||||
}
|
||||
}
|
||||
Opt::PadKeyboard => {
|
||||
let all = gamepad::TextKeyboard::ALL;
|
||||
let i = all
|
||||
@@ -1344,6 +1362,14 @@ enum WKind {
|
||||
value: f32,
|
||||
name: String,
|
||||
},
|
||||
/// A float or int option `.option` of the Horizon pack `s.shader_packs[.pack]`: where its
|
||||
/// value sits between its minimum and maximum.
|
||||
PackSlider {
|
||||
label: Text,
|
||||
value: f32,
|
||||
pack: usize,
|
||||
option: usize,
|
||||
},
|
||||
Text {
|
||||
text: Text,
|
||||
color: u32,
|
||||
@@ -1372,6 +1398,8 @@ struct Widget {
|
||||
enum FocusId {
|
||||
Search,
|
||||
Slider(Opt),
|
||||
/// A Horizon pack's option slider: (pack, option).
|
||||
PackSlider(usize, usize),
|
||||
Cycle(Opt),
|
||||
Act(Act),
|
||||
Lang(String),
|
||||
@@ -1381,6 +1409,7 @@ enum FocusId {
|
||||
fn focus_id(i: usize, wd: &Widget) -> FocusId {
|
||||
match &wd.kind {
|
||||
WKind::Slider { opt, .. } => FocusId::Slider(*opt),
|
||||
WKind::PackSlider { pack, option, .. } => FocusId::PackSlider(*pack, *option),
|
||||
WKind::Button {
|
||||
act: Act::Cycle(opt),
|
||||
..
|
||||
@@ -1394,6 +1423,9 @@ fn focus_id(i: usize, wd: &Widget) -> FocusId {
|
||||
fn matches_focus(id: &FocusId, i: usize, wd: &Widget) -> bool {
|
||||
match (id, &wd.kind) {
|
||||
(FocusId::Slider(a), WKind::Slider { opt, .. }) => a == opt,
|
||||
(FocusId::PackSlider(p, o), WKind::PackSlider { pack, option, .. }) => {
|
||||
(p, o) == (pack, option)
|
||||
}
|
||||
(
|
||||
FocusId::Cycle(a),
|
||||
WKind::Button {
|
||||
@@ -1512,6 +1544,9 @@ pub struct OptionsUi {
|
||||
/// The shader pack option whose slider is held, and the handle's own position: it follows
|
||||
/// the pointer while the option takes the nearest of its values.
|
||||
shader_dragging: Option<(String, f32)>,
|
||||
/// The same for a Horizon pack's option: (pack, option, the handle's position, whether its
|
||||
/// value changed since the press). The pack saves its values, and reloads, on release.
|
||||
pack_dragging: Option<(usize, usize, f32, bool)>,
|
||||
/// Shift is held during the click (it resets a shader pack option to its default).
|
||||
pub shift: bool,
|
||||
/// The pressed slider's own position (`AbstractSliderButton.value`) and
|
||||
@@ -1602,6 +1637,7 @@ impl Default for OptionsUi {
|
||||
scroll: 0.0,
|
||||
dragging: None,
|
||||
shader_dragging: None,
|
||||
pack_dragging: None,
|
||||
shift: false,
|
||||
slider_value: None,
|
||||
scrollbar_drag_y: None,
|
||||
@@ -1746,7 +1782,23 @@ fn native_pack_option_rows(s: &Settings, i: usize, at: u8) -> Vec<Row> {
|
||||
let value = crate::shader_pack_list::show_value(&option.kind, pack.values[o]);
|
||||
let label =
|
||||
Text::option_name_value(Text::literal(option.name.clone()), Text::literal(value));
|
||||
button(0.0, 0.0, width, label, Act::NativePackOption(i, o))
|
||||
match pack.slider_position(o) {
|
||||
Some(value) => Widget {
|
||||
x: 0.0,
|
||||
y: 0.0,
|
||||
w: width,
|
||||
h: 20.0,
|
||||
kind: WKind::PackSlider {
|
||||
label,
|
||||
value,
|
||||
pack: i,
|
||||
option: o,
|
||||
},
|
||||
list: false,
|
||||
row: 0,
|
||||
},
|
||||
None => button(0.0, 0.0, width, label, Act::NativePackOption(i, o)),
|
||||
}
|
||||
}
|
||||
PageItem::Page(p) if p < pack.pages.len() => {
|
||||
let label = Text::literal(format!("{}...", pack.pages[p].name));
|
||||
@@ -1845,7 +1897,10 @@ fn tooltip_text(s: &Settings, wd: &Widget) -> Option<Text> {
|
||||
WKind::Button {
|
||||
act: Act::NativePackOption(pack, option),
|
||||
..
|
||||
} => Some(&s.shader_packs.get(*pack)?.options.get(*option)?.description),
|
||||
}
|
||||
| WKind::PackSlider { pack, option, .. } => {
|
||||
Some(&s.shader_packs.get(*pack)?.options.get(*option)?.description)
|
||||
}
|
||||
WKind::Button {
|
||||
act: Act::Push(Page::NativePackOptions(pack, at)),
|
||||
..
|
||||
@@ -2043,6 +2098,13 @@ fn pairs(opts: &[Opt]) -> Vec<Row> {
|
||||
.collect()
|
||||
}
|
||||
impl OptionsUi {
|
||||
/// No widget keeps the highlight a click gave it; a focus the keyboard
|
||||
/// moved stays.
|
||||
pub fn clear_click_focus(&mut self) {
|
||||
if !self.focus_from_keyboard {
|
||||
self.focus = None;
|
||||
}
|
||||
}
|
||||
/// A switch of `horizon-extras.txt` as the Extras page draws it: "Caption: On".
|
||||
fn extra_button(&self, s: &Settings, item: crate::extras::Item) -> Widget {
|
||||
let label = Text::option_name_value(
|
||||
@@ -2163,6 +2225,18 @@ impl OptionsUi {
|
||||
}
|
||||
events
|
||||
}
|
||||
/// Steps a Horizon pack's option slider one step forward or backward, and saves it.
|
||||
fn step_pack_slider(s: &mut Settings, pack: usize, option: usize, forward: bool) -> Vec<Event> {
|
||||
let stepped = s
|
||||
.shader_packs
|
||||
.get_mut(pack)
|
||||
.is_some_and(|entry| entry.nudge_option(option, !forward));
|
||||
if stepped {
|
||||
vec![Event::NativePackOptions(pack)]
|
||||
} else {
|
||||
Vec::new()
|
||||
}
|
||||
}
|
||||
/// Open a page whose Done/Escape returns directly to the calling screen.
|
||||
pub fn open_at(&mut self, in_world: bool, page: Page) {
|
||||
self.stack.clear();
|
||||
@@ -2689,8 +2763,11 @@ impl OptionsUi {
|
||||
Opt::PadMoveDeadzone,
|
||||
Opt::PadLookDeadzone,
|
||||
Opt::PadGlyphs,
|
||||
Opt::PadMenuNav,
|
||||
Opt::PadKeyboard,
|
||||
Opt::PadPointerSpeed,
|
||||
Opt::PadScrollSpeed,
|
||||
Opt::PadRepeatDelay,
|
||||
Opt::PadRepeatInterval,
|
||||
]));
|
||||
rows
|
||||
}
|
||||
@@ -3716,6 +3793,34 @@ impl OptionsUi {
|
||||
dragging,
|
||||
);
|
||||
}
|
||||
WKind::PackSlider {
|
||||
label,
|
||||
value,
|
||||
pack,
|
||||
option,
|
||||
} => {
|
||||
let held = self
|
||||
.pack_dragging
|
||||
.filter(|&(p, o, ..)| (p, o) == (*pack, *option));
|
||||
let dragging = held.is_some();
|
||||
ui::slider_ext(
|
||||
batch,
|
||||
atlas,
|
||||
wd.x,
|
||||
wd.y,
|
||||
wd.w,
|
||||
label,
|
||||
held.map_or(*value, |h| h.2),
|
||||
hover || dragging,
|
||||
is_focused,
|
||||
self.can_change_value && is_focused,
|
||||
true,
|
||||
dragging,
|
||||
);
|
||||
crate::widgets::last_narratable(|n| {
|
||||
narrate_widget(n, s, wd, hover, list_key, framebuffer);
|
||||
});
|
||||
}
|
||||
WKind::Text {
|
||||
text,
|
||||
color,
|
||||
@@ -4015,6 +4120,16 @@ impl OptionsUi {
|
||||
*at = ui::slider_value(wd.x, wd.w, x);
|
||||
options.set_position(name, *at);
|
||||
}
|
||||
if let Some((pack, option, at, changed)) = &mut self.pack_dragging
|
||||
&& let Some(wd) = widgets.iter().find(|wd| {
|
||||
matches!(wd.kind, WKind::PackSlider { pack: p, option: o, .. }
|
||||
if (p, o) == (*pack, *option))
|
||||
})
|
||||
&& let Some(entry) = s.shader_packs.get_mut(*pack)
|
||||
{
|
||||
*at = ui::slider_value(wd.x, wd.w, x);
|
||||
*changed |= entry.set_slider_position(*option, *at);
|
||||
}
|
||||
if let Some(opt) = self.dragging
|
||||
&& let Some(wd) = widgets
|
||||
.iter()
|
||||
@@ -4251,6 +4366,21 @@ impl OptionsUi {
|
||||
}
|
||||
self.shader_dragging = Some((name, at));
|
||||
}
|
||||
WKind::PackSlider { pack, option, .. } => {
|
||||
self.can_change_value = true;
|
||||
let Some(entry) = s.shader_packs.get_mut(pack) else {
|
||||
break;
|
||||
};
|
||||
if self.shift {
|
||||
// Its default, as a shift-click on a pack's button does; no drag follows.
|
||||
entry.step_option(option, false, true);
|
||||
events.extend([Event::ButtonClick, Event::NativePackOptions(pack)]);
|
||||
break;
|
||||
}
|
||||
let at = ui::slider_value(wd.x, wd.w, x);
|
||||
let changed = entry.set_slider_position(option, at);
|
||||
self.pack_dragging = Some((pack, option, at, changed));
|
||||
}
|
||||
WKind::Slider { opt, .. } => {
|
||||
self.can_change_value = true;
|
||||
self.dragging = Some(opt);
|
||||
@@ -4287,12 +4417,19 @@ impl OptionsUi {
|
||||
}
|
||||
// AbstractSliderButton suppresses the press sound and plays once on
|
||||
// release, even if the pointer has left the widget or its value stayed.
|
||||
let slider = self.dragging.take().is_some() | self.shader_dragging.take().is_some();
|
||||
let pack = self.pack_dragging.take();
|
||||
let slider =
|
||||
self.dragging.take().is_some() | self.shader_dragging.take().is_some() | pack.is_some();
|
||||
let graphics_slider = self.graphics.release();
|
||||
let calibration_slider = self.calibration.as_mut().is_some_and(|c| c.release());
|
||||
let split_drop = self.split_setup.release();
|
||||
if slider || graphics_slider || calibration_slider {
|
||||
vec![Event::ButtonClick, Event::Changed]
|
||||
let mut events = vec![Event::ButtonClick, Event::Changed];
|
||||
// A pack's option is saved, and the pack rebuilt, once per drag.
|
||||
if let Some((pack, _, _, true)) = pack {
|
||||
events.push(Event::NativePackOptions(pack));
|
||||
}
|
||||
events
|
||||
} else if split_drop {
|
||||
vec![Event::ButtonClick]
|
||||
} else {
|
||||
@@ -4390,6 +4527,10 @@ impl OptionsUi {
|
||||
.map_or(150.0, |wd| wd.w);
|
||||
return self.step_slider_option(s, opt, amount > 0.0, width);
|
||||
}
|
||||
Some(FocusId::PackSlider(pack, option)) => {
|
||||
let (pack, option) = (*pack, *option);
|
||||
return Self::step_pack_slider(s, pack, option, amount > 0.0);
|
||||
}
|
||||
Some(FocusId::Cycle(opt)) => {
|
||||
let opt = *opt;
|
||||
let mut events = vec![Event::ButtonClick];
|
||||
@@ -4855,6 +4996,7 @@ impl OptionsUi {
|
||||
match wd.kind {
|
||||
WKind::Button { active: true, .. }
|
||||
| WKind::Slider { .. }
|
||||
| WKind::PackSlider { .. }
|
||||
| WKind::LanguageRow { .. } => {
|
||||
focusables.push((focus_id(i, wd), [wd.x, wd.y, wd.w, wd.h], wd.list));
|
||||
}
|
||||
@@ -4890,7 +5032,7 @@ impl OptionsUi {
|
||||
let (next_id, rect, in_list) = &focusables[next_idx];
|
||||
self.focus = Some(next_id.clone());
|
||||
self.focus_from_keyboard = true;
|
||||
self.can_change_value = matches!(next_id, FocusId::Slider(_));
|
||||
self.can_change_value = matches!(next_id, FocusId::Slider(_) | FocusId::PackSlider(..));
|
||||
if *in_list {
|
||||
if rect[1] < top {
|
||||
self.scroll -= (top - rect[1]) + 4.0;
|
||||
@@ -4915,6 +5057,11 @@ impl OptionsUi {
|
||||
.map_or(150.0, |wd| wd.w);
|
||||
return self.step_slider_option(s, opt, forward, width);
|
||||
}
|
||||
if let Some(FocusId::PackSlider(pack, option)) = self.focus
|
||||
&& self.can_change_value
|
||||
{
|
||||
return Self::step_pack_slider(s, pack, option, forward);
|
||||
}
|
||||
// Otherwise, navigate horizontally using 2D focus stepping
|
||||
if let Some(fid) = &self.focus {
|
||||
if let Some(cur_pos) = focusables.iter().position(|(id, ..)| id == fid) {
|
||||
@@ -4992,7 +5139,7 @@ impl OptionsUi {
|
||||
// 4. Enter / Space selection keys
|
||||
if matches!(key, K::Enter | K::NumpadEnter | K::Space) {
|
||||
match &self.focus {
|
||||
Some(FocusId::Slider(_)) => {
|
||||
Some(FocusId::Slider(_) | FocusId::PackSlider(..)) => {
|
||||
self.can_change_value = !self.can_change_value;
|
||||
return Vec::new();
|
||||
}
|
||||
@@ -5505,11 +5652,9 @@ mod tests {
|
||||
id: "a".into(),
|
||||
name: "A".into(),
|
||||
description: String::new(),
|
||||
kind: horizon_shader_api::OptionKind::Float {
|
||||
default: 1.0,
|
||||
min: 0.0,
|
||||
max: 2.0,
|
||||
step: 0.5,
|
||||
kind: horizon_shader_api::OptionKind::Choice {
|
||||
values: vec!["x".into(), "y".into(), "z".into()],
|
||||
default: 1,
|
||||
},
|
||||
}],
|
||||
values: vec![1.0],
|
||||
@@ -5550,10 +5695,10 @@ mod tests {
|
||||
let (x, y) = find(&mut ui, &s, &Act::NativePackOption(0, 0));
|
||||
let events = ui.click(&mut s, &atlas, x, y, size, [854, 480], false, false);
|
||||
assert!(events.contains(&Event::NativePackOptions(0)));
|
||||
assert_eq!(s.shader_packs[0].values, [1.5]);
|
||||
assert_eq!(s.shader_packs[0].values, [2.0]);
|
||||
ui.click(&mut s, &atlas, x, y, size, [854, 480], false, true);
|
||||
ui.click(&mut s, &atlas, x, y, size, [854, 480], false, true);
|
||||
assert_eq!(s.shader_packs[0].values, [0.5]);
|
||||
assert_eq!(s.shader_packs[0].values, [0.0]);
|
||||
// Shift-click: the option's default.
|
||||
ui.shift = true;
|
||||
ui.click(&mut s, &atlas, x, y, size, [854, 480], false, false);
|
||||
@@ -5567,6 +5712,116 @@ mod tests {
|
||||
assert_eq!(ui.page(), Page::NativePackOptions(0, 0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_horizon_packs_float_and_int_options_are_sliders_saved_on_release() {
|
||||
use horizon_shader_api::{OptionKind, PackOption};
|
||||
use winit::keyboard::KeyCode;
|
||||
let atlas = atlas();
|
||||
let size = (960.0, 540.0);
|
||||
let option = |id: &str, kind| PackOption {
|
||||
id: id.into(),
|
||||
name: id.into(),
|
||||
description: String::new(),
|
||||
kind,
|
||||
};
|
||||
let pack = crate::shader_pack_list::Entry {
|
||||
file: "p".into(),
|
||||
title: "P".into(),
|
||||
kind: crate::shader_pack_list::Kind::Horizon,
|
||||
options: vec![
|
||||
option(
|
||||
"a",
|
||||
OptionKind::Float {
|
||||
default: 1.0,
|
||||
min: 0.0,
|
||||
max: 2.0,
|
||||
step: 0.5,
|
||||
},
|
||||
),
|
||||
option(
|
||||
"b",
|
||||
OptionKind::Int {
|
||||
default: 2,
|
||||
min: 0,
|
||||
max: 4,
|
||||
},
|
||||
),
|
||||
option("c", OptionKind::Bool { default: true }),
|
||||
],
|
||||
values: vec![1.0, 2.0, 1.0],
|
||||
pages: Vec::new(),
|
||||
};
|
||||
let mut s = Settings {
|
||||
shader_packs: vec![pack],
|
||||
..Settings::default()
|
||||
};
|
||||
let mut ui = OptionsUi::default();
|
||||
ui.show(Page::NativePackOptions(0, 0));
|
||||
// A slider's track, from its left end to its right: (x of 0, x of 1, y).
|
||||
let track = |ui: &mut OptionsUi, s: &Settings, want: usize| {
|
||||
let (widgets, ..) = ui.layout(s, size.0, size.1);
|
||||
widgets
|
||||
.into_iter()
|
||||
.find(|w| matches!(w.kind, WKind::PackSlider { option, .. } if option == want))
|
||||
.map(|w| (w.x + 4.0, w.x + w.w - 4.0, w.y + w.h / 2.0))
|
||||
};
|
||||
assert!(track(&mut ui, &s, 2).is_none(), "a bool stays a button");
|
||||
let (left, right, y) = track(&mut ui, &s, 0).expect("the float's slider");
|
||||
let at = |f: f32| left + f * (right - left);
|
||||
// Pressed a fifth of the way: 0.4 of 2, the nearest step 0.5. Nothing is saved yet.
|
||||
let events = ui.click(&mut s, &atlas, at(0.2), y, size, [854, 480], false, false);
|
||||
assert!(!events.contains(&Event::NativePackOptions(0)));
|
||||
assert_eq!(s.shader_packs[0].values[0], 0.5);
|
||||
// Dragged past the right end: the maximum.
|
||||
ui.click(
|
||||
&mut s,
|
||||
&atlas,
|
||||
right + 30.0,
|
||||
y,
|
||||
size,
|
||||
[854, 480],
|
||||
true,
|
||||
false,
|
||||
);
|
||||
assert_eq!(s.shader_packs[0].values[0], 2.0);
|
||||
// Released: saved once, which reloads the pack.
|
||||
let events = ui.release();
|
||||
let saves = events.iter().filter(|e| **e == Event::NativePackOptions(0));
|
||||
assert_eq!(saves.count(), 1);
|
||||
// A press and release that leave the value as it was save nothing.
|
||||
ui.click(&mut s, &atlas, right, y, size, [854, 480], false, false);
|
||||
assert!(!ui.release().contains(&Event::NativePackOptions(0)));
|
||||
// Shift-click: the default at once.
|
||||
ui.shift = true;
|
||||
let events = ui.click(&mut s, &atlas, at(0.9), y, size, [854, 480], false, false);
|
||||
ui.shift = false;
|
||||
assert!(events.contains(&Event::NativePackOptions(0)));
|
||||
assert_eq!(s.shader_packs[0].values[0], 1.0);
|
||||
assert!(!ui.release().contains(&Event::NativePackOptions(0)));
|
||||
|
||||
// The int takes whole numbers: 0.6 of 0..4 is 2.4, so 2, unchanged; 0.7 is 3.
|
||||
let (left, right, y) = track(&mut ui, &s, 1).expect("the int's slider");
|
||||
let at = |f: f32| left + f * (right - left);
|
||||
ui.click(&mut s, &atlas, at(0.6), y, size, [854, 480], false, false);
|
||||
assert_eq!(s.shader_packs[0].values[1], 2.0);
|
||||
assert!(!ui.release().contains(&Event::NativePackOptions(0)));
|
||||
ui.click(&mut s, &atlas, at(0.7), y, size, [854, 480], false, false);
|
||||
assert_eq!(s.shader_packs[0].values[1], 3.0);
|
||||
assert!(ui.release().contains(&Event::NativePackOptions(0)));
|
||||
|
||||
// From the keyboard: the arrows step a focused slider, saving each step, up to its end.
|
||||
ui.focus = Some(FocusId::PackSlider(0, 1));
|
||||
ui.focus_from_keyboard = true;
|
||||
ui.can_change_value = true;
|
||||
let events = ui.key(&mut s, &atlas, KeyCode::ArrowRight, None);
|
||||
assert_eq!(events, [Event::NativePackOptions(0)]);
|
||||
assert_eq!(s.shader_packs[0].values[1], 4.0);
|
||||
assert!(ui.key(&mut s, &atlas, KeyCode::ArrowRight, None).is_empty());
|
||||
assert_eq!(s.shader_packs[0].values[1], 4.0);
|
||||
ui.key(&mut s, &atlas, KeyCode::ArrowLeft, None);
|
||||
assert_eq!(s.shader_packs[0].values[1], 3.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resource_reload_error_blocks_options_until_dismissed() {
|
||||
use winit::keyboard::KeyCode;
|
||||
@@ -8039,7 +8294,7 @@ mod tests {
|
||||
|
||||
// Also verify Act::Extra on Page::Extras
|
||||
ui.show(Page::Extras);
|
||||
let (widgets, _, _, _) = ui.layout(&s, size.0, size.1);
|
||||
let (widgets, top, _, _) = ui.layout(&s, size.0, size.1);
|
||||
if let Some(extra_btn) = widgets.iter().find(|wd| {
|
||||
matches!(
|
||||
wd.kind,
|
||||
@@ -8050,6 +8305,22 @@ mod tests {
|
||||
}
|
||||
)
|
||||
}) {
|
||||
// Extras has enough rows to scroll: click the cycle button inside
|
||||
// the list's viewport, as a player would after scrolling to it.
|
||||
ui.scroll = (extra_btn.y - top).max(0.0);
|
||||
let (widgets, _, _, _) = ui.layout(&s, size.0, size.1);
|
||||
let extra_btn = widgets
|
||||
.iter()
|
||||
.find(|wd| {
|
||||
matches!(
|
||||
wd.kind,
|
||||
WKind::Button {
|
||||
act: Act::Extra(crate::extras::Item::CosmeticsOthers),
|
||||
..
|
||||
}
|
||||
)
|
||||
})
|
||||
.unwrap();
|
||||
let (ex, ey) = (extra_btn.x + 1.0, extra_btn.y + 1.0);
|
||||
use horizon_cosmetics::prefs::Others;
|
||||
assert_eq!(s.extras.cosmetics_others, Others::Shown);
|
||||
|
||||
@@ -170,8 +170,17 @@ fn last_pre_minor(current: Format) -> i64 {
|
||||
/// `PackFormat.fullCodec(default_minor)`: an int, or a list of 1 to 256
|
||||
/// non-negative ints whose second is the minor. None: it does not parse.
|
||||
fn format_codec(v: &serde_json::Value, default_minor: i64) -> Option<Format> {
|
||||
let non_negative =
|
||||
|v: &serde_json::Value| v.as_i64().filter(|n| *n >= 0 && *n <= i64::from(i32::MAX));
|
||||
// `Codec.INT` reads any JSON number through `Number.intValue`: a decimal such as `97.1`
|
||||
// counts as its whole part (97), as it does for the game.
|
||||
let non_negative = |v: &serde_json::Value| {
|
||||
v.as_i64()
|
||||
.or_else(|| {
|
||||
v.as_f64()
|
||||
.filter(|f| f.is_finite())
|
||||
.map(|f| f.trunc() as i64)
|
||||
})
|
||||
.filter(|n| *n >= 0 && *n <= i64::from(i32::MAX))
|
||||
};
|
||||
match v {
|
||||
serde_json::Value::Array(a) if (1..=256).contains(&a.len()) => {
|
||||
let list: Option<Vec<i64>> = a.iter().map(non_negative).collect();
|
||||
@@ -636,7 +645,7 @@ fn build_overlay_uncached(
|
||||
}
|
||||
// FallbackResourceManager: a file's `.mcmeta` counts only from the pack that
|
||||
// supplies the file or one above it; vanilla's own sits below every pack.
|
||||
let hidden: BTreeSet<String> = files
|
||||
let mut hidden: BTreeSet<String> = files
|
||||
.iter()
|
||||
.filter(|(name, _)| !name.ends_with(".mcmeta"))
|
||||
.filter_map(|(name, (owner, _))| {
|
||||
@@ -647,6 +656,25 @@ fn build_overlay_uncached(
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
// A companion from below the winning colour would describe another surface.
|
||||
// A map-only pack above it is intentional and remains valid.
|
||||
for (name, (owner, _)) in &files {
|
||||
let Some(stem) = name.strip_suffix(".png") else {
|
||||
continue;
|
||||
};
|
||||
if stem.ends_with("_n") || stem.ends_with("_s") {
|
||||
continue;
|
||||
}
|
||||
for suffix in ["_n.png", "_s.png"] {
|
||||
let map = format!("{stem}{suffix}");
|
||||
if files
|
||||
.get(&map)
|
||||
.is_none_or(|(map_owner, _)| map_owner < owner)
|
||||
{
|
||||
hidden.insert(map);
|
||||
}
|
||||
}
|
||||
}
|
||||
for name in &hidden {
|
||||
files.remove(name);
|
||||
}
|
||||
@@ -1257,6 +1285,16 @@ mod tests {
|
||||
.unwrap_err()
|
||||
.contains("deprecated")
|
||||
);
|
||||
// A decimal reads as its whole part, in a list or alone: `[97.1]` is format 97 (a pack
|
||||
// that meant `[97, 1]` still loads and counts as compatible).
|
||||
assert_eq!(
|
||||
check(r#"{"min_format":[97.1],"max_format":[97.1]}"#),
|
||||
Ok(((97, 0), (97, i64::from(i32::MAX))))
|
||||
);
|
||||
assert_eq!(
|
||||
check(r#"{"min_format":97.9,"max_format":98.5}"#),
|
||||
Ok(((97, 0), (98, i64::from(i32::MAX))))
|
||||
);
|
||||
assert_eq!(
|
||||
check(r#"{"min_format":97,"max_format":98}"#),
|
||||
Ok(((97, 0), (98, i64::from(i32::MAX))))
|
||||
@@ -1469,6 +1507,61 @@ mod tests {
|
||||
assert_eq!(merge_kind("assets/minecraft/models/block/stone.json"), None);
|
||||
}
|
||||
#[test]
|
||||
fn companion_maps_follow_the_winning_colour_or_a_higher_map_only_pack() {
|
||||
let root =
|
||||
std::env::temp_dir().join(format!("horizon-material-owner-{}", std::process::id()));
|
||||
let vanilla = root.join("vanilla");
|
||||
let relative = "assets/minecraft/textures/block";
|
||||
fs::create_dir_all(vanilla.join(relative)).unwrap();
|
||||
let names = ["stone.png", "stone_n.png", "stone_s.png"];
|
||||
for name in names {
|
||||
fs::write(vanilla.join(relative).join(name), b"base").unwrap();
|
||||
}
|
||||
for (pack, files) in [
|
||||
("low", vec!["stone_n.png", "stone_s.png"]),
|
||||
("colour", vec!["stone.png"]),
|
||||
("maps", vec!["stone_n.png"]),
|
||||
] {
|
||||
let dir = root.join("packs").join(pack);
|
||||
fs::create_dir_all(dir.join(relative)).unwrap();
|
||||
fs::write(
|
||||
dir.join("pack.mcmeta"),
|
||||
br#"{"pack":{"description":"fixture","pack_format":97}}"#,
|
||||
)
|
||||
.unwrap();
|
||||
for name in files {
|
||||
fs::write(dir.join(relative).join(name), pack.as_bytes()).unwrap();
|
||||
}
|
||||
}
|
||||
let all = discover(&vanilla, &root.join("packs"));
|
||||
let order = |names: &[&str]| {
|
||||
names
|
||||
.iter()
|
||||
.map(|name| {
|
||||
all.iter()
|
||||
.find(|p| p.id == format!("file/{name}"))
|
||||
.unwrap()
|
||||
.clone()
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
};
|
||||
let out = root.join("out");
|
||||
build_overlay(&vanilla, &order(&["low", "colour"]), &out).unwrap();
|
||||
assert_eq!(
|
||||
fs::read(out.join(relative).join("stone.png")).unwrap(),
|
||||
b"colour"
|
||||
);
|
||||
assert!(!out.join(relative).join("stone_n.png").exists());
|
||||
assert!(!out.join(relative).join("stone_s.png").exists());
|
||||
build_overlay(&vanilla, &order(&["low", "colour", "maps"]), &out).unwrap();
|
||||
assert_eq!(
|
||||
fs::read(out.join(relative).join("stone_n.png")).unwrap(),
|
||||
b"maps"
|
||||
);
|
||||
assert!(!out.join(relative).join("stone_s.png").exists());
|
||||
fs::remove_dir_all(root).unwrap();
|
||||
}
|
||||
#[test]
|
||||
fn overlay_layers_packs_over_vanilla() {
|
||||
// `&` would split an unquoted `cmd /C mklink` line.
|
||||
let base = std::env::temp_dir().join(format!("horizon-packs-&{}", std::process::id()));
|
||||
|
||||
@@ -13,7 +13,7 @@ use std::{collections::BTreeSet, fs, io, path::Path, path::PathBuf};
|
||||
// Version 5 read every vanilla file to stamp it on Windows.
|
||||
// Version 6 stamps vanilla's files by their metadata on Windows too.
|
||||
// Version 7 stacks blockstate files (every pack's definition, bottom first).
|
||||
const VERSION: u32 = 7;
|
||||
const VERSION: u32 = 8;
|
||||
|
||||
#[derive(Default, Serialize, Deserialize)]
|
||||
pub(super) struct Dependencies {
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.4 KiB |
@@ -0,0 +1,67 @@
|
||||
//! The controller's menu cursor in inventories: a crosshair whose centre is
|
||||
//! the point it clicks. Horizon's own art (pad_cursor.png).
|
||||
|
||||
/// The atlas sprite.
|
||||
pub const SPRITE: &str = "horizon/pad_cursor";
|
||||
/// The texture's size in texels, and the size it's drawn at in GUI pixels
|
||||
/// (an item's).
|
||||
pub const SIZE: u32 = 32;
|
||||
pub const DRAWN: f32 = 16.0;
|
||||
|
||||
const PNG: &[u8] = include_bytes!("pad_cursor.png");
|
||||
|
||||
/// The texture as `SIZE` square RGBA texels.
|
||||
pub fn pixels() -> Vec<u8> {
|
||||
decode(PNG).expect("pad_cursor.png is a 32x32 PNG")
|
||||
}
|
||||
|
||||
fn decode(bytes: &[u8]) -> Option<Vec<u8>> {
|
||||
let mut decoder = png::Decoder::new(std::io::Cursor::new(bytes));
|
||||
decoder.set_transformations(png::Transformations::EXPAND | png::Transformations::STRIP_16);
|
||||
let mut reader = decoder.read_info().ok()?;
|
||||
let info = reader.info();
|
||||
if (info.width, info.height) != (SIZE, SIZE) {
|
||||
return None;
|
||||
}
|
||||
let mut buf = vec![0; reader.output_buffer_size()?];
|
||||
let frame = reader.next_frame(&mut buf).ok()?;
|
||||
let channels = frame.color_type.samples();
|
||||
Some(
|
||||
buf.chunks(channels)
|
||||
.take((SIZE * SIZE) as usize)
|
||||
.flat_map(|p| match channels {
|
||||
4 => [p[0], p[1], p[2], p[3]],
|
||||
3 => [p[0], p[1], p[2], 255],
|
||||
2 => [p[0], p[0], p[0], p[1]],
|
||||
_ => [p[0], p[0], p[0], 255],
|
||||
})
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
|
||||
/// Where to draw the cursor (top-left, GUI pixels) so its centre lands on
|
||||
/// the GUI point `at`.
|
||||
pub fn origin(at: (f32, f32)) -> (f32, f32) {
|
||||
(at.0 - DRAWN / 2.0, at.1 - DRAWN / 2.0)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn the_cursor_is_a_crosshair_centred_on_its_point() {
|
||||
let px = pixels();
|
||||
assert_eq!(px.len(), (SIZE * SIZE * 4) as usize);
|
||||
let alpha = |x: u32, y: u32| px[((y * SIZE + x) * 4 + 3) as usize];
|
||||
let middle = (SIZE / 2 - 1)..=(SIZE / 2);
|
||||
assert!(
|
||||
middle
|
||||
.clone()
|
||||
.any(|x| middle.clone().any(|y| alpha(x, y) > 0)),
|
||||
"the clicked point sits on the crosshair"
|
||||
);
|
||||
assert_eq!(alpha(0, 0), 0, "corners are clear: a plus, not a square");
|
||||
assert_eq!(origin((100.0, 50.0)), (92.0, 42.0));
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,8 @@ use std::{
|
||||
|
||||
pub use horizon_client_core::particle_type::ParticleType;
|
||||
pub use horizon_items::firework::{DYE_FIREWORK_COLORS, FireworkExplosion, FireworkShape};
|
||||
mod native;
|
||||
pub use native::{ParticleController, ParticleUpdate};
|
||||
|
||||
/// `ParticleOptions` with the parameters of the option classes used here.
|
||||
#[derive(Clone, Debug)]
|
||||
@@ -212,6 +214,9 @@ enum Light {
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
enum Behaviour {
|
||||
Base,
|
||||
Controlled {
|
||||
translucent: bool,
|
||||
},
|
||||
Mod {
|
||||
size: [f32; 2],
|
||||
alpha: [f32; 2],
|
||||
@@ -505,6 +510,7 @@ pub struct Particle {
|
||||
pre_tick: bool,
|
||||
/// `Particle.random`: the particle's own generator (`RandomSource.create()`).
|
||||
random: LegacyRandom,
|
||||
controller: Option<Box<dyn native::Controller>>,
|
||||
}
|
||||
fn aabb_at(p: [f64; 3], w: f32, h: f32) -> Aabb {
|
||||
let w = f64::from(w) / 2.0;
|
||||
@@ -841,8 +847,37 @@ impl Particle {
|
||||
pre_tick: false,
|
||||
frame_ticks: 0,
|
||||
random: LegacyRandom::new(0),
|
||||
controller: None,
|
||||
}
|
||||
}
|
||||
/// The normal age/removal test and previous pose, without vanilla motion.
|
||||
/// Returns false when this tick expires the particle.
|
||||
pub fn advance_age(&mut self) -> bool {
|
||||
self.previous = self.position;
|
||||
self.o_roll = self.roll;
|
||||
let alive = self.age < self.lifetime;
|
||||
self.age = self.age.saturating_add(1);
|
||||
self.removed |= !alive;
|
||||
alive
|
||||
}
|
||||
pub fn remove(&mut self) {
|
||||
self.removed = true;
|
||||
}
|
||||
/// Hide geometry while retaining the particle's lifetime and controller.
|
||||
pub fn set_visible(&mut self, visible: bool) {
|
||||
self.no_render = !visible;
|
||||
}
|
||||
/// The particle's own random, distinct from the engine and level generators.
|
||||
pub fn random(&mut self) -> &mut LegacyRandom {
|
||||
&mut self.random
|
||||
}
|
||||
pub fn set_full_bright(&mut self, full_bright: bool) {
|
||||
self.light = if full_bright {
|
||||
Light::FullBright
|
||||
} else {
|
||||
Light::World
|
||||
};
|
||||
}
|
||||
/// `Particle(level, x, y, z, xa, ya, za)`: jittered, normalized initial velocity.
|
||||
fn moving(random: &mut LegacyRandom, ty: ParticleType, p: [f64; 3], v: [f64; 3]) -> Self {
|
||||
let mut particle = Self::base_moving(random, ty, p, v);
|
||||
@@ -1420,6 +1455,10 @@ impl ParticleEngine {
|
||||
atlas: &HashMap<String, Rect>,
|
||||
translucent: &HashSet<String>,
|
||||
) {
|
||||
// Controllers' numeric sprite-set handles belong to this resource
|
||||
// generation. Discard them rather than selecting another set after reload.
|
||||
self.particles.retain(|p| p.controller.is_none());
|
||||
self.pending.retain(|p| p.controller.is_none());
|
||||
self.atlas = atlas
|
||||
.iter()
|
||||
.map(|(name, &rect)| (name.clone(), (rect, translucent.contains(name))))
|
||||
@@ -1584,6 +1623,45 @@ impl ParticleEngine {
|
||||
pub fn push(&mut self, particle: Particle) {
|
||||
self.pending.push(particle);
|
||||
}
|
||||
/// Create a named billboard with custom compiled behavior and no vanilla
|
||||
/// motion. Like `add`, respects camera distance and the Particles setting.
|
||||
/// Configure its public fields, then `push` it to the ordinary engine queue.
|
||||
/// Missing sprite sets return None. The constructor has the ordinary
|
||||
/// stationary SingleQuadParticle random size/lifetime and no velocity draws.
|
||||
pub fn controlled<C: ParticleController>(
|
||||
&mut self,
|
||||
name: &str,
|
||||
position: [f64; 3],
|
||||
translucent: bool,
|
||||
controller: C,
|
||||
) -> Option<Particle> {
|
||||
let minimal = self.calculate_particle_level(false) == 2;
|
||||
let distance: f64 = position
|
||||
.iter()
|
||||
.zip(self.camera)
|
||||
.map(|(p, c)| (p - c).powi(2))
|
||||
.sum();
|
||||
if minimal || !distance.is_finite() || distance > 1024.0 {
|
||||
return None;
|
||||
}
|
||||
let (set, _) = *self.mod_sets.get(name)?;
|
||||
let mut random = LegacyRandom::new(self.seeds.next_long());
|
||||
let mut particle = Particle::at(&mut random, ParticleType::Smoke, position);
|
||||
particle.random = random;
|
||||
particle.set = Some(set);
|
||||
particle.sprite = Sprite::Index(*self.set_sprites.get(set as usize)?.first()?);
|
||||
particle.behaviour = Behaviour::Controlled { translucent };
|
||||
particle.controller = Some(Box::new(controller));
|
||||
Some(particle)
|
||||
}
|
||||
/// Choose a frame from this particle's declared sprite set.
|
||||
pub fn set_sprite_frame(&self, particle: &mut Particle, frame: usize) {
|
||||
if let Some(sprites) = particle.set.and_then(|s| self.set_sprites.get(s as usize))
|
||||
&& !sprites.is_empty()
|
||||
{
|
||||
particle.sprite = Sprite::Index(sprites[frame.min(sprites.len() - 1)]);
|
||||
}
|
||||
}
|
||||
/// Random generator shared by particle constructors and spawners.
|
||||
pub fn random(&mut self) -> &mut LegacyRandom {
|
||||
&mut self.random
|
||||
@@ -3710,6 +3788,20 @@ impl ParticleEngine {
|
||||
fn tick_particle(&mut self, p: &mut Particle, level: &ParticleLevel) {
|
||||
match p.behaviour {
|
||||
Behaviour::Base => p.base_tick(level),
|
||||
Behaviour::Controlled { .. } => {
|
||||
if let Some(mut controller) = p.controller.take() {
|
||||
let update = controller.tick(p, level);
|
||||
p.controller = Some(controller);
|
||||
if let Some(frame) = update.frame {
|
||||
self.set_sprite_frame(p, frame);
|
||||
}
|
||||
for (options, pos, velocity) in update.spawned {
|
||||
self.add(&options, pos, velocity);
|
||||
}
|
||||
} else {
|
||||
p.remove();
|
||||
}
|
||||
}
|
||||
Behaviour::Mod { size, alpha } => {
|
||||
p.base_tick(level);
|
||||
p.size = mod_curve(size, p.age, p.lifetime);
|
||||
@@ -4627,6 +4719,7 @@ impl ParticleEngine {
|
||||
Sprite::Index(i) => (
|
||||
self.rects.get(*i as usize).copied().flatten(),
|
||||
p.ty.translucent_layer()
|
||||
|| matches!(p.behaviour, Behaviour::Controlled { translucent: true })
|
||||
|| matches!(p.behaviour, Behaviour::Mod { alpha, .. } if alpha != [1.0; 2]),
|
||||
),
|
||||
Sprite::Named(name) => match self.atlas.get(name) {
|
||||
|
||||
@@ -0,0 +1,179 @@
|
||||
//! Opt-in, compiled particle behavior. The ordinary engine still owns the
|
||||
//! particle, its sprite set, interpolation, rendering and total count limits.
|
||||
use super::{Particle, ParticleLevel, ParticleOptions};
|
||||
use std::fmt::Debug;
|
||||
|
||||
/// Requests made by one particle tick, submitted through normal spawn limits.
|
||||
#[derive(Default)]
|
||||
pub struct ParticleUpdate {
|
||||
/// An index in this particle's declared sprite set. Out-of-range is clamped.
|
||||
pub frame: Option<usize>,
|
||||
pub spawned: Vec<(ParticleOptions, [f64; 3], [f64; 3])>,
|
||||
}
|
||||
|
||||
/// Owned behavior for a compiled native particle. Cloning a particle clones its
|
||||
/// controller state. Do not retain world references; inspect `level` each tick.
|
||||
pub trait ParticleController: Clone + Debug + Send + Sync + 'static {
|
||||
/// Call `particle.advance_age()` for ordinary lifetime/interpolation, or
|
||||
/// explicitly maintain those fields for an overridden source tick.
|
||||
fn tick(&mut self, particle: &mut Particle, level: &ParticleLevel<'_>) -> ParticleUpdate;
|
||||
}
|
||||
|
||||
pub(super) trait Controller: Debug + Send + Sync {
|
||||
fn tick(&mut self, particle: &mut Particle, level: &ParticleLevel<'_>) -> ParticleUpdate;
|
||||
fn clone_box(&self) -> Box<dyn Controller>;
|
||||
}
|
||||
impl<T: ParticleController> Controller for T {
|
||||
fn tick(&mut self, particle: &mut Particle, level: &ParticleLevel<'_>) -> ParticleUpdate {
|
||||
ParticleController::tick(self, particle, level)
|
||||
}
|
||||
fn clone_box(&self) -> Box<dyn Controller> {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
}
|
||||
impl Clone for Box<dyn Controller> {
|
||||
fn clone(&self) -> Self {
|
||||
self.clone_box()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::super::*;
|
||||
use horizon_world::{
|
||||
DATA_VERSION,
|
||||
collision::CachedCollisionRegistry,
|
||||
nbt::Tag,
|
||||
registry::{BlockRegistry, BlockStateId},
|
||||
};
|
||||
#[derive(Clone, Debug)]
|
||||
struct Moving(u32);
|
||||
impl ParticleController for Moving {
|
||||
fn tick(&mut self, p: &mut Particle, _: &ParticleLevel<'_>) -> ParticleUpdate {
|
||||
if p.advance_age() {
|
||||
self.0 += 1;
|
||||
p.position[0] += f64::from(self.0);
|
||||
}
|
||||
ParticleUpdate {
|
||||
frame: Some(self.0 as usize),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
fn engine() -> ParticleEngine {
|
||||
let mut e = ParticleEngine::new(Path::new(""), &HashMap::new(), &HashSet::new());
|
||||
e.mod_sets.insert("example:orbit".into(), (0, None));
|
||||
e.set_sprites.push(vec![0, 1]);
|
||||
e.rects = vec![
|
||||
Some(Rect {
|
||||
u0: 0.0,
|
||||
v0: 0.0,
|
||||
u1: 1.0,
|
||||
v1: 1.0,
|
||||
w: 16,
|
||||
h: 16
|
||||
});
|
||||
2
|
||||
];
|
||||
e
|
||||
}
|
||||
#[test]
|
||||
fn controlled_particle_keeps_owned_motion_sprite_interpolation_and_expiry() {
|
||||
let registry = BlockRegistry::from_nbt(&Tag::compound([
|
||||
("DataVersion", Tag::Int(DATA_VERSION)),
|
||||
(
|
||||
"states",
|
||||
Tag::List(vec![Tag::String("minecraft:air".into())]),
|
||||
),
|
||||
("defaults", Tag::compound([("minecraft:air", Tag::Int(0))])),
|
||||
]))
|
||||
.unwrap();
|
||||
let cached = CachedCollisionRegistry::from_nbt(
|
||||
&Tag::compound([
|
||||
("DataVersion", Tag::Int(DATA_VERSION)),
|
||||
(
|
||||
"states",
|
||||
Tag::List(vec![Tag::String("minecraft:air".into())]),
|
||||
),
|
||||
("shapes", Tag::List(vec![])),
|
||||
("cached_shapes", Tag::IntArray(vec![-1])),
|
||||
]),
|
||||
®istry,
|
||||
)
|
||||
.unwrap();
|
||||
let collision = BlockCollisionRegistry::new(std::sync::Arc::new(cached)).unwrap();
|
||||
let facts = BlockFacts {
|
||||
states: vec![],
|
||||
air: BlockStateId(0),
|
||||
woods: HashMap::new(),
|
||||
};
|
||||
let world = World::new(BlockStateId(0), 0);
|
||||
let level = ParticleLevel {
|
||||
world: &world,
|
||||
facts: &facts,
|
||||
collision: &collision,
|
||||
player: None,
|
||||
};
|
||||
let mut e = engine();
|
||||
let mut p = e
|
||||
.controlled("example:orbit", [0.0; 3], true, Moving(0))
|
||||
.unwrap();
|
||||
p.lifetime = 2;
|
||||
p.rgba[3] = 0.5;
|
||||
p.velocity = [99.0; 3]; // no vanilla drift may leak into the custom tick
|
||||
let mut copy = p.clone();
|
||||
e.tick_particle(&mut p, &level);
|
||||
e.tick_particle(&mut p, &level);
|
||||
e.tick_particle(&mut copy, &level);
|
||||
assert_eq!((p.position, p.previous), ([3.0, 0.0, 0.0], [1.0, 0.0, 0.0]));
|
||||
assert_eq!(copy.position, [1.0, 0.0, 0.0]); // controller state cloned independently
|
||||
assert!(matches!(p.sprite, Sprite::Index(1))); // clamped frame
|
||||
p.size = 0.1;
|
||||
e.particles.push(p.clone());
|
||||
let mut vertices = Vec::new();
|
||||
e.render(DVec3::ZERO, 0.0, 0.0, 0.5, &|_| 0, &mut vertices);
|
||||
assert_eq!(vertices.len(), 4);
|
||||
assert!(vertices.iter().all(
|
||||
|v| v.color >> 24 == 127 && v.layer & crate::gfx::TRANSLUCENT_PARTICLE_OVERLAY != 0
|
||||
));
|
||||
e.particles[0].set_visible(false);
|
||||
vertices.clear();
|
||||
e.render(DVec3::ZERO, 0.0, 0.0, 0.5, &|_| 0, &mut vertices);
|
||||
assert!(vertices.is_empty());
|
||||
assert_eq!(e.particles[0].age, 2);
|
||||
e.pending.push(copy);
|
||||
e.reload(Path::new(""), &HashMap::new(), &HashSet::new());
|
||||
assert!(e.pending.is_empty());
|
||||
vertices.clear();
|
||||
e.render(DVec3::ZERO, 0.0, 0.0, 0.5, &|_| 0, &mut vertices);
|
||||
assert!(vertices.is_empty());
|
||||
e.tick_particle(&mut p, &level);
|
||||
assert!(p.removed);
|
||||
assert_eq!(p.position, [3.0, 0.0, 0.0]);
|
||||
}
|
||||
#[test]
|
||||
fn controlled_spawn_respects_distance_settings_and_declared_sprite_sets() {
|
||||
let mut e = engine();
|
||||
assert!(
|
||||
e.controlled("example:missing", [0.0; 3], true, Moving(0))
|
||||
.is_none()
|
||||
);
|
||||
assert!(
|
||||
e.controlled("example:orbit", [33.0, 0.0, 0.0], true, Moving(0))
|
||||
.is_none()
|
||||
);
|
||||
assert!(
|
||||
e.controlled("example:orbit", [f64::NAN, 0.0, 0.0], true, Moving(0))
|
||||
.is_none()
|
||||
);
|
||||
assert!(
|
||||
e.controlled("example:orbit", [32.0, 0.0, 0.0], true, Moving(0))
|
||||
.is_some()
|
||||
);
|
||||
e.particle_level = 2;
|
||||
assert!(
|
||||
e.controlled("example:orbit", [0.0; 3], true, Moving(0))
|
||||
.is_none()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -144,9 +144,6 @@ pub struct Settings {
|
||||
pub discrete_scroll: bool,
|
||||
pub toggle_crouch: bool,
|
||||
pub toggle_sprint: bool,
|
||||
/// 3D skin layers (`threeDSkinLayers`): each painted texel of a player's
|
||||
/// outer layer drawn as a slab (`crate::...`, Options → Skin).
|
||||
pub three_d_skin_layers: bool,
|
||||
pub auto_jump: bool,
|
||||
pub language: String,
|
||||
pub force_unicode: bool,
|
||||
@@ -251,7 +248,6 @@ impl Default for Settings {
|
||||
allow_cursor_changes: true,
|
||||
toggle_crouch: false,
|
||||
toggle_sprint: false,
|
||||
three_d_skin_layers: false,
|
||||
auto_jump: false,
|
||||
language: "en_us".into(),
|
||||
force_unicode: false,
|
||||
@@ -341,23 +337,28 @@ impl Settings {
|
||||
.parent()
|
||||
.map(crate::gamepad::PadSettings::load)
|
||||
.unwrap_or_default();
|
||||
let extras = path
|
||||
let extras_text = path
|
||||
.parent()
|
||||
.map(crate::extras::Extras::load)
|
||||
.and_then(|dir| fs::read_to_string(dir.join(crate::extras::FILE)).ok())
|
||||
.unwrap_or_default();
|
||||
let mut extras = crate::extras::Extras::parse(&extras_text);
|
||||
// The enabled mods are the game folder's, shared by its players (`--player-dir`).
|
||||
let mods = path
|
||||
.parent()
|
||||
.map(|dir| crate::mod_list::ModList::load(&crate::logging::shared_dir(dir)))
|
||||
.unwrap_or_default();
|
||||
let settings = match fs::read(path) {
|
||||
Ok(bytes) => Self {
|
||||
horizon,
|
||||
controller,
|
||||
extras,
|
||||
mods,
|
||||
..Self::parse(&String::from_utf8_lossy(&bytes))
|
||||
},
|
||||
Ok(bytes) => {
|
||||
let text = String::from_utf8_lossy(&bytes);
|
||||
extras.read_old_options(&extras_text, &text);
|
||||
Self {
|
||||
horizon,
|
||||
controller,
|
||||
extras,
|
||||
mods,
|
||||
..Self::parse(&text)
|
||||
}
|
||||
}
|
||||
Err(_) => Self {
|
||||
horizon,
|
||||
controller,
|
||||
@@ -463,7 +464,6 @@ impl Settings {
|
||||
allow_cursor_changes: f.bool("allowCursorChanges"),
|
||||
toggle_crouch: f.bool("toggleCrouch"),
|
||||
toggle_sprint: f.bool("toggleSprint"),
|
||||
three_d_skin_layers: f.bool("threeDSkinLayers"),
|
||||
toggle_attack: f.bool("toggleAttack"),
|
||||
toggle_use: f.bool("toggleUse"),
|
||||
sprint_window: f.int("sprintWindow"),
|
||||
@@ -575,7 +575,6 @@ impl Settings {
|
||||
put_b(&mut f, "allowCursorChanges", self.allow_cursor_changes);
|
||||
put_b(&mut f, "toggleCrouch", self.toggle_crouch);
|
||||
put_b(&mut f, "toggleSprint", self.toggle_sprint);
|
||||
put_b(&mut f, "threeDSkinLayers", self.three_d_skin_layers);
|
||||
put_b(&mut f, "toggleAttack", self.toggle_attack);
|
||||
put_b(&mut f, "toggleUse", self.toggle_use);
|
||||
put_i(&mut f, "sprintWindow", self.sprint_window);
|
||||
@@ -652,7 +651,9 @@ impl Settings {
|
||||
}
|
||||
pub fn save(&self, path: &Path) {
|
||||
self.describe_for_crashes();
|
||||
let _ = fs::write(path, self.serialize());
|
||||
if let Err(e) = fs::write(path, self.serialize()) {
|
||||
log::warn!("Horizon: options.txt is not saved: {e}");
|
||||
}
|
||||
if let Some(dir) = path.parent() {
|
||||
self.horizon.save(dir);
|
||||
self.controller.save(dir);
|
||||
@@ -804,13 +805,16 @@ pub enum Opt {
|
||||
PadAdaptiveTriggers,
|
||||
PadLightbar,
|
||||
PadLookSensitivity,
|
||||
PadPointerSpeed,
|
||||
PadScrollSpeed,
|
||||
PadRepeatDelay,
|
||||
PadRepeatInterval,
|
||||
PadInvertX,
|
||||
PadInvertY,
|
||||
PadToggleSneak,
|
||||
PadMoveDeadzone,
|
||||
PadLookDeadzone,
|
||||
PadGlyphs,
|
||||
PadMenuNav,
|
||||
PadKeyboard,
|
||||
/// `options.modelPart.*`: one skin layer (index into `options_file::MODEL_PARTS`).
|
||||
ModelPart(usize),
|
||||
@@ -852,6 +856,31 @@ mod tests {
|
||||
);
|
||||
}
|
||||
#[test]
|
||||
fn three_d_skin_layers_move_from_options_txt_to_the_extras_file() {
|
||||
// #8091 wrote the switch into options.txt; a player who had it on keeps
|
||||
// it, and the next options.txt is vanilla's again.
|
||||
let dir = std::env::temp_dir().join(format!(
|
||||
"horizon-skin-layers-{}-{:?}",
|
||||
std::process::id(),
|
||||
std::thread::current().id()
|
||||
));
|
||||
fs::create_dir_all(&dir).unwrap();
|
||||
fs::write(dir.join("options.txt"), "fov:0.5\nthreeDSkinLayers:true\n").unwrap();
|
||||
let s = Settings::load(&dir.join("options.txt"));
|
||||
assert!(s.extras.three_d_skin_layers);
|
||||
assert_eq!(s.fov, 90.0);
|
||||
assert!(!s.serialize().contains("threeDSkinLayers"));
|
||||
assert!(crate::extras::Extras::parse(&s.extras.serialize()).three_d_skin_layers);
|
||||
// Once horizon-extras.txt has its own line, a stale options.txt one is ignored.
|
||||
fs::write(dir.join(crate::extras::FILE), "threeDSkinLayers:false\n").unwrap();
|
||||
assert!(
|
||||
!Settings::load(&dir.join("options.txt"))
|
||||
.extras
|
||||
.three_d_skin_layers
|
||||
);
|
||||
let _ = fs::remove_dir_all(&dir);
|
||||
}
|
||||
#[test]
|
||||
fn an_option_set_keeps_horizon_files() {
|
||||
let mut s = Settings::parse("fov:70\n");
|
||||
s.mods.enabled.insert("zoom".into());
|
||||
|
||||
@@ -53,6 +53,47 @@ impl Entry {
|
||||
true
|
||||
}
|
||||
|
||||
/// Where option `i` sits on its slider, 0 to 1: float and int options are sliders.
|
||||
pub fn slider_position(&self, i: usize) -> Option<f32> {
|
||||
slider_position(&self.options.get(i)?.kind, *self.values.get(i)?)
|
||||
}
|
||||
|
||||
/// Option `i` at the value nearest the slider position `at`. Whether its value changed.
|
||||
pub fn set_slider_position(&mut self, i: usize, at: f32) -> bool {
|
||||
let (Some(o), Some(v)) = (self.options.get(i), self.values.get_mut(i)) else {
|
||||
return false;
|
||||
};
|
||||
let Some(new) = slider_value(&o.kind, at) else {
|
||||
return false;
|
||||
};
|
||||
let changed = new != *v;
|
||||
*v = new;
|
||||
changed
|
||||
}
|
||||
|
||||
/// Option `i`'s slider one step on (`back`: one before), stopping at its ends. Whether its
|
||||
/// value changed.
|
||||
pub fn nudge_option(&mut self, i: usize, back: bool) -> bool {
|
||||
let (Some(o), Some(v)) = (self.options.get(i), self.values.get_mut(i)) else {
|
||||
return false;
|
||||
};
|
||||
let dir = if back { -1.0 } else { 1.0 };
|
||||
let new = match &o.kind {
|
||||
OptionKind::Float { min, max, step, .. } => {
|
||||
let (min, max, step) = (f64::from(*min), f64::from(*max), f64::from(*step));
|
||||
let n = ((*v - min) / step).round() + dir;
|
||||
on_f32((min + n * step).clamp(min, max))
|
||||
}
|
||||
OptionKind::Int { min, max, .. } => {
|
||||
(v.round() + dir).clamp(f64::from(*min), f64::from(*max))
|
||||
}
|
||||
_ => return false,
|
||||
};
|
||||
let changed = new != *v;
|
||||
*v = new;
|
||||
changed
|
||||
}
|
||||
|
||||
/// Every option back to its default.
|
||||
pub fn reset_options(&mut self) {
|
||||
let defaults = self.options.iter().map(|o| o.kind.default_constant());
|
||||
@@ -209,6 +250,42 @@ fn step_value(kind: &OptionKind, v: f64, back: bool) -> f64 {
|
||||
}
|
||||
}
|
||||
|
||||
/// Where `v` sits between the option's minimum and maximum, 0 to 1; `None` for the options
|
||||
/// that are buttons.
|
||||
fn slider_position(kind: &OptionKind, v: f64) -> Option<f32> {
|
||||
let (min, max) = match kind {
|
||||
OptionKind::Float { min, max, .. } => (f64::from(*min), f64::from(*max)),
|
||||
OptionKind::Int { min, max, .. } => (f64::from(*min), f64::from(*max)),
|
||||
_ => return None,
|
||||
};
|
||||
Some(((v - min) / (max - min)).clamp(0.0, 1.0) as f32)
|
||||
}
|
||||
|
||||
/// The option's value nearest the slider position `at`: a float on its steps from the
|
||||
/// minimum (the last one the maximum, when the range isn't a whole number of steps), an int
|
||||
/// whole.
|
||||
fn slider_value(kind: &OptionKind, at: f32) -> Option<f64> {
|
||||
let at = f64::from(at.clamp(0.0, 1.0));
|
||||
match kind {
|
||||
OptionKind::Float { min, max, step, .. } => {
|
||||
let (min, max, step) = (f64::from(*min), f64::from(*max), f64::from(*step));
|
||||
let steps = ((max - min) / step - 1e-6).ceil();
|
||||
Some(on_f32((min + (at * steps).round() * step).min(max)))
|
||||
}
|
||||
OptionKind::Int { min, max, .. } => {
|
||||
let (min, max) = (f64::from(*min), f64::from(*max));
|
||||
Some((min + at * (max - min)).round())
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// `v` as the `f32` the pack's `override` gets: a step of 0.05 is no f32, and 20 of them would
|
||||
/// otherwise miss a default of 1 by a hair.
|
||||
fn on_f32(v: f64) -> f64 {
|
||||
f64::from(v as f32)
|
||||
}
|
||||
|
||||
/// The value as the settings page shows it.
|
||||
pub fn show_value(kind: &OptionKind, v: f64) -> String {
|
||||
match kind {
|
||||
@@ -324,4 +401,65 @@ mod tests {
|
||||
assert_eq!(load_values(&pack, &options), [1.0, 0.0]);
|
||||
std::fs::remove_dir_all(&dir).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sliders_take_the_nearest_step_and_stop_at_the_ends() {
|
||||
let float = |default, max, step| OptionKind::Float {
|
||||
default,
|
||||
min: 0.0,
|
||||
max,
|
||||
step,
|
||||
};
|
||||
let int = OptionKind::Int {
|
||||
default: 2,
|
||||
min: 0,
|
||||
max: 10,
|
||||
};
|
||||
let mut entry = Entry {
|
||||
file: "p".into(),
|
||||
title: "P".into(),
|
||||
kind: Kind::Horizon,
|
||||
options: vec![
|
||||
option("a", float(1.0, 2.0, 0.05)),
|
||||
option("b", int),
|
||||
option("c", OptionKind::Bool { default: true }),
|
||||
option("d", float(0.0, 1.0, 0.3)),
|
||||
],
|
||||
values: vec![1.0, 2.0, 1.0, 0.0],
|
||||
pages: Vec::new(),
|
||||
};
|
||||
assert_eq!(entry.slider_position(0), Some(0.5));
|
||||
assert_eq!(entry.slider_position(1), Some(0.2));
|
||||
// A bool (and a choice) stays a button.
|
||||
assert_eq!(entry.slider_position(2), None);
|
||||
assert!(!entry.set_slider_position(2, 0.0));
|
||||
assert_eq!(entry.values[2], 1.0);
|
||||
// 0.26 of 0..2 is 0.52: the step below.
|
||||
assert!(entry.set_slider_position(0, 0.26));
|
||||
assert_eq!(show_value(&entry.options[0].kind, entry.values[0]), "0.50");
|
||||
// Twenty steps of 0.05 are the default of 1 exactly, so it isn't saved.
|
||||
assert!(entry.set_slider_position(0, 0.5));
|
||||
assert_eq!(entry.values[0], 1.0);
|
||||
assert!(!entry.set_slider_position(0, 0.505));
|
||||
// 5.7 of 0..10 is 6.
|
||||
assert!(entry.set_slider_position(1, 0.57));
|
||||
assert_eq!(entry.values[1], 6.0);
|
||||
// A range that isn't a whole number of steps still reaches its maximum.
|
||||
entry.set_slider_position(3, 1.0);
|
||||
assert_eq!(entry.values[3], 1.0);
|
||||
entry.set_slider_position(3, 0.6);
|
||||
assert_eq!(entry.values[3], f64::from(0.6_f32));
|
||||
|
||||
// The arrow keys: a step at a time, not round past the ends.
|
||||
entry.values[0] = 2.0;
|
||||
assert!(!entry.nudge_option(0, false));
|
||||
assert_eq!(entry.values[0], 2.0);
|
||||
assert!(entry.nudge_option(0, true));
|
||||
assert_eq!(entry.values[0], f64::from(1.95_f32));
|
||||
entry.values[1] = 0.0;
|
||||
assert!(!entry.nudge_option(1, true));
|
||||
assert!(entry.nudge_option(1, false));
|
||||
assert_eq!(entry.values[1], 1.0);
|
||||
assert!(!entry.nudge_option(2, false));
|
||||
}
|
||||
}
|
||||
@@ -68,27 +68,48 @@ fn cpu_if_enabled() -> Option<Duration> {
|
||||
/// Run `f`, recording its duration under `name` when spans are enabled.
|
||||
#[inline]
|
||||
pub fn time<T>(name: &'static str, f: impl FnOnce() -> T) -> T {
|
||||
let _span = guard(name);
|
||||
f()
|
||||
}
|
||||
/// A span that ends where it is dropped: [`time`] for a step with several ways out (early
|
||||
/// returns). Nothing is read while spans are off.
|
||||
#[must_use = "the span ends when the guard is dropped"]
|
||||
pub struct Guard {
|
||||
open: Option<(&'static str, Instant, Option<Duration>, u8)>,
|
||||
_heap: Option<horizon_threads::heap_census::Tag>,
|
||||
}
|
||||
/// Start a span named `name` that ends when the returned [`Guard`] is dropped.
|
||||
#[inline]
|
||||
pub fn guard(name: &'static str) -> Guard {
|
||||
let _heap = horizon_threads::heap_tag(name);
|
||||
if !recording_here() {
|
||||
return f();
|
||||
return Guard { open: None, _heap };
|
||||
}
|
||||
let depth = DEPTH.with(|d| d.replace(d.get().saturating_add(1)));
|
||||
let (started, cpu) = (Instant::now(), cpu_if_enabled());
|
||||
let out = f();
|
||||
let ms = started.elapsed().as_secs_f32() * 1000.0;
|
||||
let cpu_ms = cpu
|
||||
.and_then(|start| Some((thread_cpu()?, start)))
|
||||
.map_or(ms, |(end, start)| (end - start).as_secs_f32() * 1000.0);
|
||||
DEPTH.with(|d| d.set(depth));
|
||||
SPANS.with(|s| {
|
||||
s.borrow_mut().push(Span {
|
||||
name,
|
||||
ms,
|
||||
cpu_ms,
|
||||
depth,
|
||||
})
|
||||
});
|
||||
out
|
||||
Guard {
|
||||
open: Some((name, Instant::now(), cpu_if_enabled(), depth)),
|
||||
_heap,
|
||||
}
|
||||
}
|
||||
impl Drop for Guard {
|
||||
fn drop(&mut self) {
|
||||
let Some((name, started, cpu, depth)) = self.open.take() else {
|
||||
return;
|
||||
};
|
||||
let ms = started.elapsed().as_secs_f32() * 1000.0;
|
||||
let cpu_ms = cpu
|
||||
.and_then(|start| Some((thread_cpu()?, start)))
|
||||
.map_or(ms, |(end, start)| (end - start).as_secs_f32() * 1000.0);
|
||||
DEPTH.with(|d| d.set(depth));
|
||||
SPANS.with(|s| {
|
||||
s.borrow_mut().push(Span {
|
||||
name,
|
||||
ms,
|
||||
cpu_ms,
|
||||
depth,
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
/// Notes that one step inside a span took `ms` milliseconds doing `what` (one player's
|
||||
/// packets, say), when this thread records spans and the step took at least [`NOTE_MS`]: a
|
||||
@@ -551,6 +572,42 @@ mod tests {
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
/// A guarded span ends on every way out of its step, an early return's too, and holds the
|
||||
/// spans that ran inside it until then; the next span outside it is back at its depth.
|
||||
#[test]
|
||||
fn a_guarded_span_ends_where_its_step_returns() {
|
||||
fn step(early: bool) -> u32 {
|
||||
let _span = super::guard("use_block");
|
||||
super::time("open_loot", || ());
|
||||
if early {
|
||||
return 1;
|
||||
}
|
||||
super::time("open_maps", || ());
|
||||
2
|
||||
}
|
||||
std::thread::spawn(|| {
|
||||
super::record_here(true);
|
||||
assert_eq!(step(true), 1);
|
||||
assert_eq!(step(false), 2);
|
||||
super::time("use_item", || ());
|
||||
let raw = super::take_raw();
|
||||
let seen: Vec<_> = raw.iter().map(|s| (s.name, s.depth)).collect();
|
||||
assert_eq!(
|
||||
seen,
|
||||
[
|
||||
("open_loot", 1),
|
||||
("use_block", 0),
|
||||
("open_loot", 1),
|
||||
("open_maps", 1),
|
||||
("use_block", 0),
|
||||
("use_item", 0)
|
||||
]
|
||||
);
|
||||
})
|
||||
.join()
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
/// A slow frame is put down to the slowest outer span, then to the span inside it that took
|
||||
/// at least half of it; repeated spans (several ticks a frame) add up.
|
||||
#[test]
|
||||
|
||||
@@ -8,6 +8,7 @@ pub struct SpriteAnimation {
|
||||
pub layer: u32,
|
||||
frames: Arc<Vec<Vec<u8>>>,
|
||||
clip: Arc<AnimationClip>,
|
||||
materials: [Option<Arc<Vec<Vec<u8>>>>; 2],
|
||||
}
|
||||
/// What an animated sprite shows: `frame`, mixed `millis` thousandths of the
|
||||
/// way towards `next` (0 for a single frame).
|
||||
@@ -18,6 +19,14 @@ pub struct FrameBlend {
|
||||
pub millis: u32,
|
||||
}
|
||||
impl SpriteAnimation {
|
||||
pub(crate) fn has_materials(&self) -> bool {
|
||||
self.materials.iter().any(Option::is_some)
|
||||
}
|
||||
/// Material categories follow the selected colour frame, without colour interpolation.
|
||||
pub(crate) fn material_pixels(&self, kind: usize, tick: u64) -> Option<&[u8]> {
|
||||
let frames = self.materials[kind].as_ref()?;
|
||||
Some(&frames[self.frame(tick) % frames.len()])
|
||||
}
|
||||
pub fn frame(&self, tick: u64) -> usize {
|
||||
self.clip.sample(tick).frame as usize
|
||||
}
|
||||
@@ -88,9 +97,9 @@ pub struct Sprites {
|
||||
/// Each layer's frames at the texture's own resolution (square), and the
|
||||
/// frame shown first.
|
||||
native: Vec<(u32, Arc<Vec<Vec<u8>>>, usize)>,
|
||||
/// Each layer's LabPBR maps (`_n` normals, `_s` specular) beside its texture: their first
|
||||
/// frame at their own resolution (square).
|
||||
pbr: Vec<[Option<(u32, Vec<u8>)>; 2]>,
|
||||
/// Each layer's LabPBR maps (`_n` normals, `_s` specular) beside its texture: their
|
||||
/// frames at their own resolution (square).
|
||||
pbr: Vec<[Option<(u32, Vec<Vec<u8>>)>; 2]>,
|
||||
/// The layers' normal and specular maps at `pbr_size`, layer after layer, set by
|
||||
/// [`Sprites::finish`]: empty when no texture has either.
|
||||
pub normals: Vec<u8>,
|
||||
@@ -126,7 +135,7 @@ pub fn set_texture_budget(mib: u32) {
|
||||
/// Whether resource loads read the resource packs' LabPBR maps (`set_labpbr_maps`).
|
||||
static LABPBR_MAPS: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false);
|
||||
/// Whether resource loads from now on read the resource packs' LabPBR maps beside their block
|
||||
/// textures. Only a native shader pack's material stage reads them, so without one they cost
|
||||
/// textures. Native material stages and terrain shader packs read them; without a pack they cost
|
||||
/// neither loading time nor video memory.
|
||||
pub fn set_labpbr_maps(on: bool) {
|
||||
LABPBR_MAPS.store(on, std::sync::atomic::Ordering::Relaxed);
|
||||
@@ -135,7 +144,7 @@ pub fn set_labpbr_maps(on: bool) {
|
||||
pub fn labpbr_maps() -> bool {
|
||||
LABPBR_MAPS.load(std::sync::atomic::Ordering::Relaxed)
|
||||
}
|
||||
/// Largest array of each LabPBR map, which only a native shader pack reads.
|
||||
/// Budget for either complete normal or specular image set.
|
||||
const MAX_MAP_BYTES: u64 = DEFAULT_TEXTURE_BUDGET / 4;
|
||||
/// Fewer layers than any game has (vanilla's are about 1300): what a map is kept at while
|
||||
/// loading assumes at least these many share the array.
|
||||
@@ -153,30 +162,12 @@ fn side_within(start: u32, layers: u64, bytes: u64) -> u32 {
|
||||
}
|
||||
size
|
||||
}
|
||||
/// A LabPBR map's square `frame` of `side` averaged down by whole powers of two to at most
|
||||
/// `max`, channel by channel: they are data, not colour.
|
||||
/// Reduce data maps by selecting whole texels: material IDs and sentinel bytes cannot be averaged.
|
||||
fn shrink_map(frame: Vec<u8>, side: u32, max: u32) -> (u32, Vec<u8>) {
|
||||
if side <= max || !side.is_power_of_two() || !max.is_power_of_two() {
|
||||
return (side, frame);
|
||||
}
|
||||
let (out_side, f, side) = (max as usize, (side / max) as usize, side as usize);
|
||||
let mut out = Vec::with_capacity(out_side * out_side * 4);
|
||||
for y in 0..out_side {
|
||||
for x in 0..out_side {
|
||||
let mut sum = [0u32; 4];
|
||||
for dy in 0..f {
|
||||
let row = ((y * f + dy) * side + x * f) * 4;
|
||||
for texel in frame[row..row + f * 4].as_chunks::<4>().0 {
|
||||
for (s, &v) in sum.iter_mut().zip(texel) {
|
||||
*s += u32::from(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
let n = (f * f) as u32;
|
||||
out.extend(sum.map(|s| ((s + n / 2) / n) as u8));
|
||||
}
|
||||
}
|
||||
(max, out)
|
||||
(max, resample(&frame, side, max))
|
||||
}
|
||||
/// Nearest-resample a square RGBA frame to another square size.
|
||||
pub(crate) fn resample(frame: &[u8], from: u32, to: u32) -> Vec<u8> {
|
||||
@@ -289,14 +280,28 @@ impl Sprites {
|
||||
if largest_map.is_some() {
|
||||
let pbr_size = self.pbr_size;
|
||||
log::info!("Horizon: LabPBR maps at {pbr_size} px, {layers} layers");
|
||||
for maps in std::mem::take(&mut self.pbr) {
|
||||
for animation in &mut self.animations {
|
||||
animation.materials = self.pbr[animation.layer as usize].each_ref().map(|map| {
|
||||
map.as_ref().map(|(from, frames)| {
|
||||
Arc::new(
|
||||
frames
|
||||
.iter()
|
||||
.map(|frame| resample(frame, *from, pbr_size))
|
||||
.collect(),
|
||||
)
|
||||
})
|
||||
});
|
||||
}
|
||||
for (layer, maps) in std::mem::take(&mut self.pbr).into_iter().enumerate() {
|
||||
for (map, (out, none)) in maps.into_iter().zip([
|
||||
(&mut self.normals, FLAT_NORMAL),
|
||||
(&mut self.specular, NO_SPECULAR),
|
||||
]) {
|
||||
match map {
|
||||
Some((from, pixels)) => {
|
||||
let (from, pixels) = shrink_map(pixels, from, pbr_size);
|
||||
Some((from, frames)) => {
|
||||
let initial = self.native[layer].2 % frames.len();
|
||||
let (from, pixels) =
|
||||
shrink_map(frames[initial].clone(), from, pbr_size);
|
||||
out.extend(resample(&pixels, from, pbr_size));
|
||||
}
|
||||
None => out.extend(none.repeat((pbr_size * pbr_size) as usize)),
|
||||
@@ -638,8 +643,10 @@ impl Sprites {
|
||||
let pbr = match name.split_once(':') {
|
||||
Some(_) if labpbr_maps() => {
|
||||
let path = crate::atlas_sources::texture_path(root, name, "textures");
|
||||
["_n", "_s"].map(|suffix| pbr_map(&path, suffix, count))
|
||||
["_n", "_s"].map(|suffix| pbr_map(&path, suffix, count, animation.as_ref()))
|
||||
}
|
||||
None if labpbr_maps() && !name.starts_with("fusion/") => ["_n", "_s"]
|
||||
.map(|suffix| pbr_map(&root.join(name), suffix, count, animation.as_ref())),
|
||||
_ => [None, None],
|
||||
};
|
||||
let settings = crate::mipmap::Settings {
|
||||
@@ -691,6 +698,7 @@ impl Sprites {
|
||||
layer,
|
||||
frames: frames.clone(),
|
||||
clip: Arc::new(clip),
|
||||
materials: [None, None],
|
||||
});
|
||||
}
|
||||
self.mips.push(settings);
|
||||
@@ -734,32 +742,64 @@ fn read_rgba(path: &Path) -> Result<(u32, u32, Vec<u8>)> {
|
||||
Ok((info.width, info.height, pixels))
|
||||
}
|
||||
|
||||
/// The LabPBR map with `suffix` beside the texture at `path`, whose frames lie in a column of
|
||||
/// `count`: its first frame, square, no larger than the maps' array allows any game's
|
||||
/// textures (a 512x pack's maps would otherwise fill the memory while loading).
|
||||
fn pbr_map(path: &Path, suffix: &str, count: u32) -> Option<(u32, Vec<u8>)> {
|
||||
/// Companion frames use the colour image's grid; a single-frame map stays static.
|
||||
fn pbr_map(
|
||||
path: &Path,
|
||||
suffix: &str,
|
||||
count: u32,
|
||||
animation: Option<&AnimationMetadata>,
|
||||
) -> Option<(u32, Vec<Vec<u8>>)> {
|
||||
let stem = path.file_stem()?.to_str()?;
|
||||
let map = path.with_file_name(format!("{stem}{suffix}.png"));
|
||||
let (map_width, map_height, pixels) = read_rgba(&map).ok()?;
|
||||
let (w, h) = (map_width, map_height / count.max(1));
|
||||
let (width, height, _) = read_rgba(path).ok()?;
|
||||
let [frame_width, frame_height] = animation.map_or([width as i32, height as i32], |a| {
|
||||
a.frame_size(width as i32, height as i32)
|
||||
});
|
||||
let (frame_width, frame_height) = (
|
||||
u32::try_from(frame_width).ok()?,
|
||||
u32::try_from(frame_height).ok()?,
|
||||
);
|
||||
if frame_width == 0 || frame_height == 0 {
|
||||
return None;
|
||||
}
|
||||
let (columns, rows) = if count <= 1 || (map_width == frame_width && map_height == frame_height)
|
||||
{
|
||||
(1, 1)
|
||||
} else if u64::from(map_width) * u64::from(height) == u64::from(map_height) * u64::from(width) {
|
||||
(width / frame_width, height / frame_height)
|
||||
} else if u64::from(map_width) * u64::from(frame_height)
|
||||
== u64::from(map_height) * u64::from(frame_width)
|
||||
{
|
||||
(1, 1)
|
||||
} else {
|
||||
return None;
|
||||
};
|
||||
if columns == 0 || rows == 0 || map_width % columns != 0 || map_height % rows != 0 {
|
||||
return None;
|
||||
}
|
||||
let (w, h) = (map_width / columns, map_height / rows);
|
||||
if w == 0 || h == 0 {
|
||||
return None;
|
||||
}
|
||||
let side = w.max(h);
|
||||
let mut frame = Vec::with_capacity((side * side * 4) as usize);
|
||||
for row in 0..side {
|
||||
for column in 0..side {
|
||||
let offset = (((row * h / side) * map_width + column * w / side) * 4) as usize;
|
||||
frame.extend_from_slice(&pixels[offset..offset + 4]);
|
||||
}
|
||||
}
|
||||
Some(shrink_map(
|
||||
frame,
|
||||
side,
|
||||
side_within(side, LAYERS_AT_LEAST, MAX_MAP_BYTES),
|
||||
))
|
||||
let output_side = side_within(side, LAYERS_AT_LEAST, MAX_MAP_BYTES).min(side);
|
||||
let frames = (0..columns * rows)
|
||||
.map(|index| {
|
||||
let (x, y) = (index % columns * w, index / columns * h);
|
||||
let mut frame = Vec::with_capacity((side * side * 4) as usize);
|
||||
for row in 0..side {
|
||||
for column in 0..side {
|
||||
let offset =
|
||||
(((y + row * h / side) * map_width + x + column * w / side) * 4) as usize;
|
||||
frame.extend_from_slice(&pixels[offset..offset + 4]);
|
||||
}
|
||||
}
|
||||
resample(&frame, side, output_side)
|
||||
})
|
||||
.collect();
|
||||
Some((output_side, frames))
|
||||
}
|
||||
|
||||
/// SpriteContents: the `.mcmeta` `texture` section (TextureMetadataSection's
|
||||
/// mipmap strategy and alpha cutoff bias).
|
||||
fn texture_section(
|
||||
@@ -790,6 +830,7 @@ pub(crate) fn test_frames(layer: u32, frames: Vec<Vec<u8>>, metadata: &str) -> S
|
||||
layer,
|
||||
clip: Arc::new(metadata.clip(frames.len() as u32).unwrap().unwrap()),
|
||||
frames: Arc::new(frames),
|
||||
materials: [None, None],
|
||||
}
|
||||
}
|
||||
|
||||
@@ -815,8 +856,8 @@ mod tests {
|
||||
assert_eq!(side_within(512, 1300, 1), SPRITE_SIZE);
|
||||
}
|
||||
#[test]
|
||||
fn a_labpbr_map_shrinks_by_plain_means_and_a_layer_without_one_gets_the_default() {
|
||||
// Alpha is data here: it does not weigh the other channels.
|
||||
fn a_labpbr_map_selects_whole_texels_and_missing_layers_get_defaults() {
|
||||
// Selecting a texel preserves encoded channels, including categorical values.
|
||||
let frame = [
|
||||
[200, 100, 0, 255],
|
||||
[0, 0, 0, 0],
|
||||
@@ -824,14 +865,14 @@ mod tests {
|
||||
[0, 0, 0, 0],
|
||||
]
|
||||
.concat();
|
||||
assert_eq!(shrink_map(frame, 2, 1), (1, vec![100, 50, 0, 128]));
|
||||
assert_eq!(shrink_map(frame, 2, 1), (1, vec![200, 100, 0, 255]));
|
||||
let mut sprites = Sprites {
|
||||
native: vec![
|
||||
(SPRITE_SIZE, Arc::new(vec![vec![0; 16 * 16 * 4]]), 0),
|
||||
(SPRITE_SIZE, Arc::new(vec![vec![0; 16 * 16 * 4]]), 0),
|
||||
],
|
||||
pbr: vec![
|
||||
[Some((16, [9, 8, 7, 6].repeat(16 * 16))), None],
|
||||
[Some((16, vec![[9, 8, 7, 6].repeat(16 * 16)])), None],
|
||||
[None, None],
|
||||
],
|
||||
..Default::default()
|
||||
@@ -844,6 +885,50 @@ mod tests {
|
||||
assert_eq!(sprites.specular.len(), 2 * 16 * 16 * 4);
|
||||
}
|
||||
#[test]
|
||||
fn companion_grid_and_static_map_follow_colour_frame_selection() {
|
||||
let root =
|
||||
std::env::temp_dir().join(format!("horizon-companion-grid-{}", std::process::id()));
|
||||
fs::create_dir_all(&root).unwrap();
|
||||
let write = |name: &str, width, height, pixels: &[u8]| {
|
||||
let mut encoder =
|
||||
png::Encoder::new(File::create(root.join(name)).unwrap(), width, height);
|
||||
encoder.set_color(png::ColorType::Rgba);
|
||||
encoder.set_depth(png::BitDepth::Eight);
|
||||
encoder
|
||||
.write_header()
|
||||
.unwrap()
|
||||
.write_image_data(pixels)
|
||||
.unwrap();
|
||||
};
|
||||
write("grid.png", 4, 4, &[200, 200, 200, 255].repeat(16));
|
||||
let maps: Vec<u8> = (0..16)
|
||||
.flat_map(|i| {
|
||||
let cell = (i / 8) * 2 + (i % 4) / 2;
|
||||
[10 + cell as u8, 230, 65, 255]
|
||||
})
|
||||
.collect();
|
||||
write("grid_s.png", 4, 4, &maps);
|
||||
write("grid_n.png", 2, 2, &[128, 128, 255, 255].repeat(4));
|
||||
let metadata =
|
||||
r#"{"width":2,"height":2,"frametime":2,"interpolate":true,"frames":[3,1,2,0]}"#;
|
||||
let animation = AnimationMetadata::from_json(metadata).unwrap();
|
||||
let (side, frames) = pbr_map(&root.join("grid.png"), "_s", 4, Some(&animation)).unwrap();
|
||||
assert_eq!(side, 2);
|
||||
assert_eq!(
|
||||
frames.iter().map(|f| f[0]).collect::<Vec<_>>(),
|
||||
[10, 11, 12, 13]
|
||||
);
|
||||
let (_, normals) = pbr_map(&root.join("grid.png"), "_n", 4, Some(&animation)).unwrap();
|
||||
assert_eq!(normals.len(), 1);
|
||||
let mut sprite = test_frames(0, vec![vec![0; 16]; 4], metadata);
|
||||
sprite.materials = [Some(Arc::new(normals)), Some(Arc::new(frames))];
|
||||
for (tick, expected) in [(0, 13), (1, 13), (2, 11), (4, 12), (6, 10)] {
|
||||
assert_eq!(sprite.material_pixels(1, tick).unwrap()[0], expected);
|
||||
assert_eq!(&sprite.material_pixels(0, tick).unwrap()[..4], &FLAT_NORMAL);
|
||||
}
|
||||
fs::remove_dir_all(root).unwrap();
|
||||
}
|
||||
#[test]
|
||||
fn textures_without_labpbr_maps_keep_none() {
|
||||
let mut sprites = Sprites {
|
||||
native: vec![(SPRITE_SIZE, Arc::new(vec![vec![0; 16 * 16 * 4]]), 0)],
|
||||
@@ -1284,6 +1369,7 @@ mod tests {
|
||||
fn animation_boundaries_and_repeated_frames_do_not_depend_on_render_rate() {
|
||||
let animation = SpriteAnimation {
|
||||
layer: 0,
|
||||
materials: [None, None],
|
||||
frames: Arc::new(vec![vec![], vec![], vec![]]),
|
||||
clip: Arc::new(AnimationMetadata::from_json(r#"{"frames":[{"index":2,"time":8},{"index":1,"time":3},{"index":1,"time":2},0]}"#).unwrap().clip(3).unwrap().unwrap()),
|
||||
};
|
||||
|
||||
@@ -386,6 +386,7 @@ impl World {
|
||||
chunk.motion_blocking(x & 15, z & 15, |v| blocks(BlockStateId(v)))
|
||||
})
|
||||
}
|
||||
#[inline]
|
||||
pub fn block(&self, x: i32, y: i32, z: i32) -> BlockStateId {
|
||||
self.chunks
|
||||
.get(&(x >> 4, z >> 4))
|
||||
|
||||
@@ -0,0 +1,162 @@
|
||||
//! An ordinary read of a struct or buffer-block member that an atomic function also uses gets
|
||||
//! the member's current value (#9081), on a host GPU through the translated program.
|
||||
|
||||
use horizon_shaders::{Macros, Pack, preprocess, translate_compute};
|
||||
|
||||
/// Runs compute program `source` once (one work group), with `probe_buffer` (set 4, binding 2)
|
||||
/// starting at `start`, and returns `probe_result.result` (set 4, binding 1).
|
||||
fn run(device: &wgpu::Device, queue: &wgpu::Queue, source: &str, start: [u32; 2]) -> u32 {
|
||||
use std::io::Write;
|
||||
use wgpu::util::DeviceExt;
|
||||
let mut zip = zip::ZipWriter::new(std::io::Cursor::new(Vec::new()));
|
||||
zip.start_file(
|
||||
"shaders/deferred.csh",
|
||||
zip::write::SimpleFileOptions::default(),
|
||||
)
|
||||
.unwrap();
|
||||
zip.write_all(source.as_bytes()).unwrap();
|
||||
let pack =
|
||||
Pack::from_zip_bytes("atomic-values.zip", zip.finish().unwrap().into_inner()).unwrap();
|
||||
let program = translate_compute(&preprocess(&pack, "deferred.csh", &Macros::standard()))
|
||||
.unwrap_or_else(|e| panic!("{e:?}"));
|
||||
let module = device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
||||
label: None,
|
||||
source: wgpu::ShaderSource::Naga(std::borrow::Cow::Owned(program.module)),
|
||||
});
|
||||
let pipeline = device.create_compute_pipeline(&wgpu::ComputePipelineDescriptor {
|
||||
label: None,
|
||||
layout: None,
|
||||
module: &module,
|
||||
entry_point: Some("main"),
|
||||
compilation_options: Default::default(),
|
||||
cache: None,
|
||||
});
|
||||
let storage = wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_SRC;
|
||||
let uniforms = device.create_buffer(&wgpu::BufferDescriptor {
|
||||
label: None,
|
||||
size: u64::from(program.interface.uniform_size.max(48)),
|
||||
usage: wgpu::BufferUsages::UNIFORM,
|
||||
mapped_at_creation: false,
|
||||
});
|
||||
let result = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||
label: None,
|
||||
contents: &[0; 4],
|
||||
usage: storage,
|
||||
});
|
||||
let probe: Vec<u8> = start.iter().flat_map(|v| v.to_le_bytes()).collect();
|
||||
let probe = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||
label: None,
|
||||
contents: &probe,
|
||||
usage: storage,
|
||||
});
|
||||
let read = device.create_buffer(&wgpu::BufferDescriptor {
|
||||
label: None,
|
||||
size: 4,
|
||||
usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::MAP_READ,
|
||||
mapped_at_creation: false,
|
||||
});
|
||||
let groups: Vec<wgpu::BindGroup> = (0..5)
|
||||
.map(|set| {
|
||||
let entries: Vec<wgpu::BindGroupEntry> = match set {
|
||||
0 => vec![wgpu::BindGroupEntry {
|
||||
binding: 0,
|
||||
resource: uniforms.as_entire_binding(),
|
||||
}],
|
||||
4 if source.contains("probe_buffer") => vec![
|
||||
wgpu::BindGroupEntry {
|
||||
binding: 1,
|
||||
resource: result.as_entire_binding(),
|
||||
},
|
||||
wgpu::BindGroupEntry {
|
||||
binding: 2,
|
||||
resource: probe.as_entire_binding(),
|
||||
},
|
||||
],
|
||||
4 => vec![wgpu::BindGroupEntry {
|
||||
binding: 1,
|
||||
resource: result.as_entire_binding(),
|
||||
}],
|
||||
_ => Vec::new(),
|
||||
};
|
||||
device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||
label: None,
|
||||
layout: &pipeline.get_bind_group_layout(set),
|
||||
entries: &entries,
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
let mut encoder = device.create_command_encoder(&Default::default());
|
||||
{
|
||||
let mut pass = encoder.begin_compute_pass(&Default::default());
|
||||
pass.set_pipeline(&pipeline);
|
||||
for (set, group) in groups.iter().enumerate() {
|
||||
pass.set_bind_group(set as u32, group, &[]);
|
||||
}
|
||||
pass.dispatch_workgroups(1, 1, 1);
|
||||
}
|
||||
encoder.copy_buffer_to_buffer(&result, 0, &read, 0, 4);
|
||||
queue.submit([encoder.finish()]);
|
||||
read.slice(..)
|
||||
.map_async(wgpu::MapMode::Read, |r| r.unwrap());
|
||||
device.poll(wgpu::PollType::wait_indefinitely()).unwrap();
|
||||
let bytes = read.slice(..).get_mapped_range().unwrap();
|
||||
u32::from_le_bytes(bytes[..4].try_into().unwrap())
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore = "requires a host GPU; run with --ignored --nocapture"]
|
||||
fn reads_of_atomic_members_see_the_atomic_updates() {
|
||||
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor::new_without_display_handle());
|
||||
let adapter = pollster::block_on(instance.request_adapter(&Default::default())).unwrap();
|
||||
eprintln!("Atomic member GPU: {}", adapter.get_info().name);
|
||||
// Pack buffers sit in bind group 4, as in the game.
|
||||
let (device, queue) = pollster::block_on(adapter.request_device(&wgpu::DeviceDescriptor {
|
||||
required_limits: wgpu::Limits {
|
||||
max_bind_groups: 5,
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
}))
|
||||
.unwrap();
|
||||
let result = "layout(std430, binding = 1) buffer probe_result { uint result; };\n";
|
||||
// Eight invocations each add 1 to a zeroed shared member, then read it: 8.
|
||||
for (host, member) in [
|
||||
("shared struct { uint other; uint count; } sh;", "sh.count"),
|
||||
(
|
||||
"struct Counter { uint count; uint other; };\nshared Counter counters[2];",
|
||||
"counters[1].count",
|
||||
),
|
||||
] {
|
||||
for (read, expected) in [
|
||||
("result = M * 10u + 1u;", 81),
|
||||
("uint r = M; result = r;", 8),
|
||||
("result = uint(float(M) * 0.5);", 4),
|
||||
("result = min(M, 5u);", 5),
|
||||
] {
|
||||
let source = format!(
|
||||
"#version 460 core\nlayout(local_size_x = 8) in;\n{host}\n{result}\
|
||||
void main() {{\n {member} = 0u;\n barrier();\n \
|
||||
atomicAdd({member}, 1u);\n barrier();\n {}\n}}\n",
|
||||
read.replace('M', member)
|
||||
);
|
||||
assert_eq!(
|
||||
run(&device, &queue, &source, [0, 0]),
|
||||
expected,
|
||||
"{member}: {read}"
|
||||
);
|
||||
}
|
||||
}
|
||||
// One invocation adds 2 to a buffer member that starts at 5, then reads it: 7.
|
||||
for (read, expected) in [
|
||||
("result = pc.count * 10u + 1u;", 71),
|
||||
("uint r = pc.count; result = r;", 7),
|
||||
("result = uint(int(pc.count) - 10 + 100);", 97),
|
||||
] {
|
||||
let source = format!(
|
||||
"#version 460 core\nlayout(local_size_x = 1) in;\n\
|
||||
layout(std430, binding = 2) buffer probe_buffer {{ uint count; uint other; }} pc;\n\
|
||||
{result}void main() {{\n atomicAdd(pc.count, 2u);\n {read}\n}}\n"
|
||||
);
|
||||
assert_eq!(run(&device, &queue, &source, [5, 0]), expected, "{read}");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,208 @@
|
||||
//! Synthetic rendering checks (two output shapes mirror RenderPearl v2.7.2 @86de79c, MIT; see the
|
||||
//! PR): a fragment output's `component` layout qualifier (GLSL 4.60, 4.4.2) picks the channels of
|
||||
//! its location that it writes.
|
||||
use horizon_shaders::{Origin, Preprocessed, Target, translate_composite};
|
||||
|
||||
fn source(code: &str) -> Preprocessed {
|
||||
Preprocessed {
|
||||
code: code.into(),
|
||||
files: vec!["components.glsl".into()],
|
||||
lines: code
|
||||
.lines()
|
||||
.enumerate()
|
||||
.map(|(i, _)| Origin {
|
||||
file: 0,
|
||||
line: i as u32 + 1,
|
||||
})
|
||||
.collect(),
|
||||
version: Some((440, None)),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
/// Draws `fragment` over a 1×1 target of `format` and reads back its 16 bytes.
|
||||
fn draw(
|
||||
device: &wgpu::Device,
|
||||
queue: &wgpu::Queue,
|
||||
fragment: &str,
|
||||
format: wgpu::TextureFormat,
|
||||
) -> [u8; 16] {
|
||||
let program = translate_composite(
|
||||
&source("void main() { gl_Position = ftransform(); }"),
|
||||
&source(fragment),
|
||||
Target::Buffers,
|
||||
)
|
||||
.unwrap_or_else(|e| panic!("{fragment}: {e:?}"));
|
||||
let module = |module| {
|
||||
device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
||||
label: None,
|
||||
source: wgpu::ShaderSource::Naga(std::borrow::Cow::Owned(module)),
|
||||
})
|
||||
};
|
||||
let (vertex, fragment_module) = (module(program.vertex), module(program.fragment));
|
||||
let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||
label: None,
|
||||
layout: None,
|
||||
vertex: wgpu::VertexState {
|
||||
module: &vertex,
|
||||
entry_point: Some("main"),
|
||||
compilation_options: Default::default(),
|
||||
buffers: &[],
|
||||
},
|
||||
primitive: wgpu::PrimitiveState {
|
||||
topology: wgpu::PrimitiveTopology::TriangleStrip,
|
||||
..Default::default()
|
||||
},
|
||||
depth_stencil: None,
|
||||
multisample: Default::default(),
|
||||
fragment: Some(wgpu::FragmentState {
|
||||
module: &fragment_module,
|
||||
entry_point: Some("main"),
|
||||
compilation_options: Default::default(),
|
||||
targets: &[Some(wgpu::ColorTargetState {
|
||||
format,
|
||||
blend: None,
|
||||
write_mask: wgpu::ColorWrites::ALL,
|
||||
})],
|
||||
}),
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
let extent = wgpu::Extent3d {
|
||||
width: 1,
|
||||
height: 1,
|
||||
depth_or_array_layers: 1,
|
||||
};
|
||||
let target = device.create_texture(&wgpu::TextureDescriptor {
|
||||
label: None,
|
||||
size: extent,
|
||||
mip_level_count: 1,
|
||||
sample_count: 1,
|
||||
dimension: wgpu::TextureDimension::D2,
|
||||
format,
|
||||
usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_SRC,
|
||||
view_formats: &[],
|
||||
});
|
||||
let readback = device.create_buffer(&wgpu::BufferDescriptor {
|
||||
label: None,
|
||||
size: 256,
|
||||
usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::MAP_READ,
|
||||
mapped_at_creation: false,
|
||||
});
|
||||
let view = target.create_view(&Default::default());
|
||||
let mut encoder = device.create_command_encoder(&Default::default());
|
||||
{
|
||||
let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||
label: None,
|
||||
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
||||
view: &view,
|
||||
resolve_target: None,
|
||||
depth_slice: None,
|
||||
ops: wgpu::Operations {
|
||||
load: wgpu::LoadOp::Clear(wgpu::Color::TRANSPARENT),
|
||||
store: wgpu::StoreOp::Store,
|
||||
},
|
||||
})],
|
||||
..Default::default()
|
||||
});
|
||||
pass.set_pipeline(&pipeline);
|
||||
// The composite program's uniform block, if it kept one, reads zero.
|
||||
if program.interface.uniform_size > 0 {
|
||||
let buffer = device.create_buffer(&wgpu::BufferDescriptor {
|
||||
label: None,
|
||||
size: u64::from(program.interface.uniform_size).max(16),
|
||||
usage: wgpu::BufferUsages::UNIFORM,
|
||||
mapped_at_creation: false,
|
||||
});
|
||||
let group = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||
label: None,
|
||||
layout: &pipeline.get_bind_group_layout(0),
|
||||
entries: &[wgpu::BindGroupEntry {
|
||||
binding: 0,
|
||||
resource: buffer.as_entire_binding(),
|
||||
}],
|
||||
});
|
||||
pass.set_bind_group(0, &group, &[]);
|
||||
}
|
||||
pass.draw(0..4, 0..1);
|
||||
}
|
||||
encoder.copy_texture_to_buffer(
|
||||
target.as_image_copy(),
|
||||
wgpu::TexelCopyBufferInfo {
|
||||
buffer: &readback,
|
||||
layout: wgpu::TexelCopyBufferLayout {
|
||||
offset: 0,
|
||||
bytes_per_row: Some(256),
|
||||
rows_per_image: Some(1),
|
||||
},
|
||||
},
|
||||
extent,
|
||||
);
|
||||
queue.submit([encoder.finish()]);
|
||||
readback
|
||||
.slice(..)
|
||||
.map_async(wgpu::MapMode::Read, |r| r.unwrap());
|
||||
device.poll(wgpu::PollType::wait_indefinitely()).unwrap();
|
||||
let bytes = readback.slice(..).get_mapped_range().unwrap()[..16]
|
||||
.try_into()
|
||||
.unwrap();
|
||||
readback.unmap();
|
||||
bytes
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore = "requires a host GPU; run with --ignored --nocapture"]
|
||||
fn component_qualified_outputs_write_their_own_channels() {
|
||||
let instance =
|
||||
wgpu::Instance::new(wgpu::InstanceDescriptor::new_without_display_handle().with_env());
|
||||
let adapter = pollster::block_on(instance.request_adapter(&Default::default()))
|
||||
.expect("GPU adapter required; missing adapter is not a pass");
|
||||
eprintln!("Output components GPU: {:?}", adapter.get_info());
|
||||
assert_ne!(adapter.get_info().device_type, wgpu::DeviceType::Cpu);
|
||||
let (device, queue) = pollster::block_on(adapter.request_device(&Default::default())).unwrap();
|
||||
// The channels no output writes keep the fill of a narrow output: 0, and 1 in alpha.
|
||||
for (name, fragment, expected) in [
|
||||
(
|
||||
"uvec3 at component 1",
|
||||
"layout(location = 0, component = 1) out uvec3 words;\n\
|
||||
void main() { words = uvec3(7u, 8u, 9u); }",
|
||||
[0u32, 7, 8, 9],
|
||||
),
|
||||
(
|
||||
"uint at component 2",
|
||||
"layout(location = 0, component = 2) out uint word;\n\
|
||||
void main() { word = 5u; }",
|
||||
[0, 0, 5, 1],
|
||||
),
|
||||
(
|
||||
"two outputs share location 0",
|
||||
"layout(location = 0, component = 0) out uint low;\n\
|
||||
layout(location = 0, component = 1) out uvec3 high;\n\
|
||||
void main() { low = 3u; high = uvec3(4u, 5u, 6u); }",
|
||||
[3, 4, 5, 6],
|
||||
),
|
||||
(
|
||||
"the component 1 output declared first",
|
||||
"layout(location = 0, component = 1) out uvec2 middle;\n\
|
||||
layout(location = 0) out uint low;\n\
|
||||
void main() { low = 11u; middle = uvec2(12u, 13u); }",
|
||||
[11, 12, 13, 1],
|
||||
),
|
||||
] {
|
||||
let bytes = draw(&device, &queue, fragment, wgpu::TextureFormat::Rgba32Uint);
|
||||
let actual: [u32; 4] = bytemuck::cast(bytes);
|
||||
eprintln!("{name}: {actual:?}");
|
||||
assert_eq!(actual, expected, "{name}");
|
||||
}
|
||||
let bytes = draw(
|
||||
&device,
|
||||
&queue,
|
||||
"layout(location = 0, component = 0) out float red;\n\
|
||||
layout(location = 0, component = 1) out vec3 rest;\n\
|
||||
void main() { red = 0.0; rest = vec3(1.0, 0.0, 1.0); }",
|
||||
wgpu::TextureFormat::Rgba32Float,
|
||||
);
|
||||
let actual: [f32; 4] = bytemuck::cast(bytes);
|
||||
eprintln!("float outputs share location 0: {actual:?}");
|
||||
assert_eq!(actual, [0.0, 1.0, 0.0, 1.0]);
|
||||
}
|
||||
@@ -0,0 +1,191 @@
|
||||
//! Original synthetic rendering controls for ordinary uniform initial values.
|
||||
use horizon_client_render::gfx::pack_uniforms::Value;
|
||||
use horizon_shaders::{Origin, Preprocessed, Target, translate_composite};
|
||||
use wgpu::util::DeviceExt;
|
||||
|
||||
fn source(code: &str) -> Preprocessed {
|
||||
Preprocessed {
|
||||
code: code.into(),
|
||||
files: vec!["original-render.glsl".into()],
|
||||
lines: code
|
||||
.lines()
|
||||
.enumerate()
|
||||
.map(|(i, _)| Origin {
|
||||
file: 0,
|
||||
line: i as u32 + 1,
|
||||
})
|
||||
.collect(),
|
||||
version: Some((430, None)),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore = "requires a host GPU; run with --ignored --nocapture"]
|
||||
fn authored_defaults_render_and_runtime_values_override_including_zero() {
|
||||
let program = translate_composite(
|
||||
&source("void main() { gl_Position = ftransform(); }"),
|
||||
&source("uniform float gain = 0.375; uniform mat3 basis = mat3(2.0); uniform mat4 transform = mat4(1.0); uniform vec3 tint = vec3(0.125,0.25,0.5); uniform float points[2] = float[](0.0625,0.125); uniform int mode = 3; uniform bool enabled = true; out vec4 color; void main() { color = vec4(gain * basis[0][0] * transform[2][2], tint.g + points[1], float(mode), enabled ? 1.0 : 0.0); }"),
|
||||
Target::Buffers,
|
||||
).unwrap();
|
||||
let instance =
|
||||
wgpu::Instance::new(wgpu::InstanceDescriptor::new_without_display_handle().with_env());
|
||||
let adapter = pollster::block_on(instance.request_adapter(&Default::default()))
|
||||
.expect("GPU adapter required; missing adapter is not a pass");
|
||||
eprintln!("Uniform defaults GPU: {:?}", adapter.get_info());
|
||||
assert_ne!(adapter.get_info().device_type, wgpu::DeviceType::Cpu);
|
||||
let (device, queue) = pollster::block_on(adapter.request_device(&Default::default())).unwrap();
|
||||
let vertex = device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
||||
label: None,
|
||||
source: wgpu::ShaderSource::Naga(std::borrow::Cow::Owned(program.vertex)),
|
||||
});
|
||||
let fragment = device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
||||
label: None,
|
||||
source: wgpu::ShaderSource::Naga(std::borrow::Cow::Owned(program.fragment)),
|
||||
});
|
||||
let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||
label: None,
|
||||
layout: None,
|
||||
vertex: wgpu::VertexState {
|
||||
module: &vertex,
|
||||
entry_point: Some("main"),
|
||||
compilation_options: Default::default(),
|
||||
buffers: &[],
|
||||
},
|
||||
primitive: wgpu::PrimitiveState {
|
||||
topology: wgpu::PrimitiveTopology::TriangleStrip,
|
||||
..Default::default()
|
||||
},
|
||||
depth_stencil: None,
|
||||
multisample: Default::default(),
|
||||
fragment: Some(wgpu::FragmentState {
|
||||
module: &fragment,
|
||||
entry_point: Some("main"),
|
||||
compilation_options: Default::default(),
|
||||
targets: &[Some(wgpu::ColorTargetState {
|
||||
format: wgpu::TextureFormat::Rgba32Float,
|
||||
blend: None,
|
||||
write_mask: wgpu::ColorWrites::ALL,
|
||||
})],
|
||||
}),
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
let target = device.create_texture(&wgpu::TextureDescriptor {
|
||||
label: None,
|
||||
size: wgpu::Extent3d {
|
||||
width: 1,
|
||||
height: 1,
|
||||
depth_or_array_layers: 1,
|
||||
},
|
||||
mip_level_count: 1,
|
||||
sample_count: 1,
|
||||
dimension: wgpu::TextureDimension::D2,
|
||||
format: wgpu::TextureFormat::Rgba32Float,
|
||||
usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_SRC,
|
||||
view_formats: &[],
|
||||
});
|
||||
let readback = device.create_buffer(&wgpu::BufferDescriptor {
|
||||
label: None,
|
||||
size: 256,
|
||||
usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::MAP_READ,
|
||||
mapped_at_creation: false,
|
||||
});
|
||||
for (name, zero_buffer, overrides, expected) in [
|
||||
("authored defaults", false, vec![], [0.75, 0.375, 3.0, 1.0]),
|
||||
(
|
||||
"runtime precedence",
|
||||
false,
|
||||
vec![
|
||||
("gain", Value::F([0.125; 16])),
|
||||
("transform", Value::F([0.5; 16])),
|
||||
("mode", Value::I([7, 0, 0])),
|
||||
("enabled", Value::I([0; 3])),
|
||||
],
|
||||
[0.125, 0.375, 7.0, 0.0],
|
||||
),
|
||||
(
|
||||
"runtime explicit zero",
|
||||
false,
|
||||
vec![("gain", Value::F([0.; 16])), ("mode", Value::I([0; 3]))],
|
||||
[0.0, 0.375, 0.0, 1.0],
|
||||
),
|
||||
("zero upload negative control", true, vec![], [0.; 4]),
|
||||
] {
|
||||
let mut bytes = if zero_buffer {
|
||||
vec![0; program.interface.uniform_size as usize]
|
||||
} else {
|
||||
program.interface.initial_values.clone()
|
||||
};
|
||||
for (name, value) in overrides {
|
||||
let uniform = program
|
||||
.interface
|
||||
.uniforms
|
||||
.iter()
|
||||
.find(|u| u.name == name)
|
||||
.unwrap();
|
||||
value.write(&uniform.ty, &mut bytes, uniform.offset as usize);
|
||||
}
|
||||
let buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||
label: Some(name),
|
||||
contents: &bytes,
|
||||
usage: wgpu::BufferUsages::UNIFORM,
|
||||
});
|
||||
let group = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||
label: None,
|
||||
layout: &pipeline.get_bind_group_layout(0),
|
||||
entries: &[wgpu::BindGroupEntry {
|
||||
binding: 0,
|
||||
resource: buffer.as_entire_binding(),
|
||||
}],
|
||||
});
|
||||
let view = target.create_view(&Default::default());
|
||||
let mut encoder = device.create_command_encoder(&Default::default());
|
||||
{
|
||||
let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||
label: None,
|
||||
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
||||
view: &view,
|
||||
resolve_target: None,
|
||||
depth_slice: None,
|
||||
ops: wgpu::Operations {
|
||||
load: wgpu::LoadOp::Clear(wgpu::Color::TRANSPARENT),
|
||||
store: wgpu::StoreOp::Store,
|
||||
},
|
||||
})],
|
||||
..Default::default()
|
||||
});
|
||||
pass.set_pipeline(&pipeline);
|
||||
pass.set_bind_group(0, &group, &[]);
|
||||
pass.draw(0..4, 0..1);
|
||||
}
|
||||
encoder.copy_texture_to_buffer(
|
||||
target.as_image_copy(),
|
||||
wgpu::TexelCopyBufferInfo {
|
||||
buffer: &readback,
|
||||
layout: wgpu::TexelCopyBufferLayout {
|
||||
offset: 0,
|
||||
bytes_per_row: Some(256),
|
||||
rows_per_image: Some(1),
|
||||
},
|
||||
},
|
||||
wgpu::Extent3d {
|
||||
width: 1,
|
||||
height: 1,
|
||||
depth_or_array_layers: 1,
|
||||
},
|
||||
);
|
||||
queue.submit([encoder.finish()]);
|
||||
readback
|
||||
.slice(..)
|
||||
.map_async(wgpu::MapMode::Read, |r| r.unwrap());
|
||||
device.poll(wgpu::PollType::wait_indefinitely()).unwrap();
|
||||
{
|
||||
let mapped = readback.slice(..).get_mapped_range().unwrap();
|
||||
let actual: &[f32] = bytemuck::cast_slice(&mapped[..16]);
|
||||
eprintln!("{name}: {actual:?}");
|
||||
assert_eq!(actual, expected, "{name}");
|
||||
}
|
||||
readback.unmap();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,479 @@
|
||||
{
|
||||
"horizon.options.controller": "Beheerder",
|
||||
"horizon.options.vibration": "Vibrasie",
|
||||
"horizon.options.adaptive_triggers": "Aanpasbare snellers",
|
||||
"horizon.options.lightbar": "Ligbalk",
|
||||
"horizon.options.look_sensitivity": "Kyksensitiwiteit",
|
||||
"horizon.options.invert_x": "Omgekeerde kyk X",
|
||||
"horizon.options.invert_y": "Omgekeerde kyk Y",
|
||||
"horizon.options.sneak_button": "Sluipknoppie",
|
||||
"horizon.options.move_deadzone": "Bewegingsdooiesone",
|
||||
"horizon.options.look_deadzone": "Kykdooiesone",
|
||||
"horizon.options.button_glyphs": "Knoppie Glyphs",
|
||||
"horizon.options.on_screen_keyboard": "Sleutelbord op die skerm",
|
||||
"horizon.options.chat_delay": "Chat Vertraging",
|
||||
"horizon.options.lightbar.health": "Gesondheid",
|
||||
"horizon.options.lightbar.dimension": "Dimensie",
|
||||
"horizon.options.glyphs.auto": "Outo",
|
||||
"horizon.options.keyboard.auto": "Outo",
|
||||
"horizon.options.unavailable": "Hierdie kenmerk is nog nie in Horizon beskikbaar nie.",
|
||||
"horizon.options.search": "Soek instellings...",
|
||||
"horizon.pages.shader_packs": "Shader Pakke",
|
||||
"horizon.pages.shader_options": "Shader Opsies",
|
||||
"horizon.pages.controller": "Beheerderinstellings",
|
||||
"horizon.pages.controller_binds": "Kontroleerder bind",
|
||||
"horizon.pages.extras": "Horizon-ekstras",
|
||||
"horizon.pages.settings": "Horizon-instellings",
|
||||
"horizon.pages.agent": "KI Agent",
|
||||
"horizon.split.leave": "Los",
|
||||
"horizon.pages.split_settings": "Verdeelskerm-instellings",
|
||||
"horizon.pages.split_profiles": "Wie speel?",
|
||||
"horizon.pages.split_setup": "Verdeelskerm-opstelling",
|
||||
"horizon.pages.music": "Musiek",
|
||||
"horizon.pages.music.menu": "Spyskaart",
|
||||
"horizon.pages.music.overworld": "Oorwêreld",
|
||||
"horizon.pages.music.creative": "Kreatief",
|
||||
"horizon.pages.music.underwater": "Onderwater",
|
||||
"horizon.pages.music.end": "Die Einde",
|
||||
"horizon.pages.music.boss": "Baas",
|
||||
"horizon.pages.music.credits": "Krediete",
|
||||
"horizon.pages.music.overworld_biomes": "Oorwêreld biome",
|
||||
"horizon.pages.music.nether_biomes": "Onder biome",
|
||||
"horizon.pages.music.end_biomes": "Eindig biome",
|
||||
"horizon.pages.music.other": "Ander musiek",
|
||||
"horizon.pages.music.empty": "Geen musieksnitte nie: die speletjie se klanke is nie gelaai nie.",
|
||||
"horizon.pages.music.tooltip": "Die ingeboude snitte, volgens situasie: speel nou een, of skakel enige af sodat die speletjie ophou om dit te kies.",
|
||||
"horizon.pages.settings.tooltip": "Horizon se eie instellings: grafika, beheerders, ekstras en mods.",
|
||||
"horizon.pages.graphics.tooltip": "Grafika, eenvoudig: elke instelling sê wat dit kos.",
|
||||
"horizon.pages.graphics_advanced.tooltip": "Elke grafiese instelling, Horizon s'n ingesluit, met wat elkeen kos.",
|
||||
"horizon.pages.controller.tooltip": "Beheerders: hul knoppies, stokke, vibrasie en spyskaartnavigasie.",
|
||||
"horizon.pages.extras.tooltip": "Opsionele toevoegings, alles by verstek af: die speletjie bly vanielje totdat jy een aanskakel.",
|
||||
"horizon.pages.agent.tooltip": "Laat jou eie KI-agent speel: horizon-ctl en MCP-kliënte op hierdie rekenaar.",
|
||||
"horizon.pages.split_profiles.tooltip": "Wie speel: 'n profiel wat in hierdie speletjie-lêergids gehou word.",
|
||||
"horizon.pages.split_setup.tooltip": "Die vensters en monitors, en wie speel waar.",
|
||||
"horizon.pages.shader_packs.tooltip": "Shader-pakke vanaf die shaderpacks-lêergids: Horizon se eie en dié in die shaders/formaat. Een hardloop op 'n slag.",
|
||||
"horizon.pages.mods.tooltip": "Mods gemaak vir Horizon, vanaf die horizon-mods-lêergids. Elkeen loop in 'n sandbox en bly af totdat jy dit aanskakel.",
|
||||
"horizon.pages.open.graphics": "Grafika...",
|
||||
"horizon.pages.open.graphics_advanced": "Gevorderde grafika...",
|
||||
"horizon.pages.open.shader_packs": "Shader-pakke...",
|
||||
"horizon.pages.open.controller": "Beheerderinstellings...",
|
||||
"horizon.pages.open.split_setup": "Verdeelskerm...",
|
||||
"horizon.pages.open.extras": "Ekstras...",
|
||||
"horizon.pages.open.mods": "Modusse...",
|
||||
"horizon.pages.open.agent": "KI Agent...",
|
||||
"horizon.pages.open.horizon_graphics": "Horizon-grafika...",
|
||||
"horizon.pages.open.controller_binds": "Beheerder bind...",
|
||||
"horizon.pages.open.horizon_settings": "Horizon-instellings...",
|
||||
"horizon.pages.open.music": "Musiek...",
|
||||
"horizon.mods.empty": "Geen mods: plaas .hmod-lêers in die horizon-mods-lêergids",
|
||||
"horizon.mods.stopped": " (Gestop)",
|
||||
"horizon.mods.not_built": " (Nie gebou nie)",
|
||||
"horizon.mods.dev": " (Ontwikkelaar)",
|
||||
"horizon.mods.settings": "Instellings",
|
||||
"horizon.mods.in_world": " (los die wêreld om te verander)",
|
||||
"horizon.mods.open_folder": "Maak Mod-lêergids oop",
|
||||
"horizon.shader_packs.empty": "Geen shader packs: plaas dit in die shaderpacks-lêergids",
|
||||
"horizon.shader_options.open": "Shader-opsies...",
|
||||
"horizon.shader_options.profile": "Profiel",
|
||||
"horizon.shader_options.loading": "Lees tans die shader-pakket se opsies...",
|
||||
"horizon.agent.copy_details": "Kopieer verbindingbesonderhede",
|
||||
"horizon.multiplayer.join": "Sluit aan",
|
||||
"horizon.multiplayer.cancel_reconnecting": "Kanselleer Herkoppel",
|
||||
"horizon.multiplayer.join_friend": "Sluit aan by 'n Vriend",
|
||||
"horizon.multiplayer.invite_code": "Uitnodigingskode",
|
||||
"horizon.multiplayer.relay": "Aflos (opsioneel)",
|
||||
"Preset": "Vooraf ingesteld",
|
||||
"LOD Distance": "LOD Afstand",
|
||||
"Far Detail": "Verre Detail",
|
||||
"Cave Culling": "Grotuitdunning",
|
||||
"Entity Culling": "Entiteit Uitdunning",
|
||||
"Upload Budget": "Laai begroting op",
|
||||
"Sky": "Hemel",
|
||||
"Fog": "Mis",
|
||||
"Weather": "Weer",
|
||||
"Animated Textures": "Geanimeerde teksture",
|
||||
"Present Mode": "Aanbiedingsmodus",
|
||||
"Frame Pacing": "Raamtempo",
|
||||
"Worker Threads": "Werkerdrade",
|
||||
"Resolution Scale": "Resolusieskaal",
|
||||
"Upscaling": "Opskaling",
|
||||
"Paper White": "Papier Wit",
|
||||
"Peak Brightness": "Piek helderheid",
|
||||
"Black Level": "Swart vlak",
|
||||
"UI Brightness": "UI Helderheid",
|
||||
"Battery Mode": "Batterymodus",
|
||||
"Graphics API": "Grafiese API",
|
||||
"Translucent Batching": "Deurskynende Batching",
|
||||
"Performance Overlay": "Prestasie-oorleg",
|
||||
"Full Detail Distance": "Volledige detail Afstand",
|
||||
"On": "Aan",
|
||||
"Off": "Af",
|
||||
"Unlimited": "Onbeperk",
|
||||
"Auto": "Outo",
|
||||
"Custom": "Pasgemaak",
|
||||
"Performance": "Prestasie",
|
||||
"Balanced": "Gebalanseerd",
|
||||
"Quality": "Kwaliteit",
|
||||
"Ultra Performance": "Ultra prestasie",
|
||||
"Native": "Inheems",
|
||||
"Full": "Vol",
|
||||
"Reduced": "Verminder",
|
||||
"Efficient": "Doeltreffend",
|
||||
"Precise": "Presies",
|
||||
"Auto (VSync)": "Outo (VSync)",
|
||||
"FIFO": "EIEU",
|
||||
"Mailbox": "Posbus",
|
||||
"Immediate": "Onmiddellik",
|
||||
"FPS and Graph": "FPS en grafiek",
|
||||
"No cost": "Geen koste nie",
|
||||
"Low cost": "Lae koste",
|
||||
"Medium cost": "Medium koste",
|
||||
"High cost": "Hoë koste",
|
||||
"Saves time": "Spaar tyd",
|
||||
"Graphics": "Grafika",
|
||||
"Done": "Klaar",
|
||||
"This feature is not yet available in Horizon.": "Hierdie kenmerk is nog nie in Horizon beskikbaar nie.",
|
||||
"Your display or system doesn't offer HDR output.": "Jou skerm of stelsel bied nie HDR-uitvoer nie.",
|
||||
"Turn HDR on to use it.": "Skakel HDR aan om dit te gebruik.",
|
||||
"Your GPU or graphics API doesn't support it.": "Jou GPU of grafiese API ondersteun dit nie.",
|
||||
"%s chunks": "%s stukke",
|
||||
"%s per frame": "%s per raam",
|
||||
"%s MiB/frame": "%s MiB/raam",
|
||||
"%s KiB/frame": "%s KiB/raam",
|
||||
"Auto (%s)": "Outo (%s)",
|
||||
"Full-detail terrain range. LOD Distance can extend local worlds farther.": "Volledige detail terreinreeks. LOD Distance kan plaaslike wêrelde verder uitbrei.",
|
||||
"Coarse distant terrain in local worlds. Integrated GPUs stop at 128 chunks.": "Growwe verre terrein in plaaslike wêrelde. Geïntegreerde GPU's stop by 128 stukke.",
|
||||
"Reduced draws far terrain coarser: faster on this integrated GPU.": "Verminder trek veel terrein growwer: vinniger op hierdie geïntegreerde GPU.",
|
||||
"Reduced draws far terrain coarser, for GPUs it slows down.": "Verminder trek veel terrein growwer, vir GPU's word dit stadiger.",
|
||||
"Field of view. Wider shows more terrain at once.": "Gesigsveld. Wyer wys meer terrein op een slag.",
|
||||
"Caps frames per second; a cap saves power and heat.": "Caps rame per sekonde; 'n pet spaar krag en hitte.",
|
||||
"Waits for the display's refresh: no tearing, a little latency.": "Wag vir die verversing van die skerm: geen skeur nie, 'n bietjie vertraging.",
|
||||
"Size of menus and the HUD.": "Grootte van spyskaarte en die HUD.",
|
||||
"Sets the options below together. Changing one makes it Custom.": "Stel die opsies hieronder saam. Om een te verander, maak dit Pasgemaak.",
|
||||
"Lava, fire and sunlight shine brighter than white. Needs an HDR display.": "Lava, vuur en sonlig skyn helderder as wit. Benodig 'n HDR-skerm.",
|
||||
"Your display's darkest black. 0 for OLED; LCDs glow a little.": "Jou skerm is die donkerste swart. 0 vir OLED; LCD's gloei 'n bietjie.",
|
||||
"How bright highlights get. Auto: the peak your system reports.": "Hoe helder hoogtepunte word. Outo: die hoogtepunt wat jou stelsel rapporteer.",
|
||||
"How bright white paper and menus look. Auto: your desktop's white.": "Hoe helder wit papier en spyskaarte lyk. Outo: jou lessenaar is wit.",
|
||||
"How bright the HUD and menus are, against paper white.": "Hoe helder die HUD en spyskaarte is, teenoor papierwit.",
|
||||
"How far mobs, crops and machines keep working. CPU time.": "Hoe ver skare, gewasse en masjiene aanhou werk. SVE tyd.",
|
||||
"How far away mobs and items are drawn, as a share of normal.": "Hoe ver weg skares en items getrek word, as 'n deel van normaal.",
|
||||
"Skips terrain hidden behind closed sections. Off costs a lot.": "Slaan terrein oor wat agter geslote gedeeltes versteek is. Af kos baie.",
|
||||
"Hides entities behind opaque blocks.": "Versteek entiteite agter ondeursigtige blokke.",
|
||||
"No entity occlusion culling.": "Geen entiteit-okklusion uitskot nie.",
|
||||
"CPU occlusion test runs this frame.": "SVE-okklusietoets loop hierdie raam.",
|
||||
"Occlusion checks run on a worker thread.": "Okklusiekontroles loop op 'n werkersdraad.",
|
||||
"Meshed sections uploaded per frame. Lower is smoother while loading.": "Maasafdelings per raam opgelaai. Laer is gladder tydens laai.",
|
||||
"Soft shadows in corners. Costs chunk building time only.": "Sagte skaduwees in hoeke. Dit kos slegs 'n stuk boutyd.",
|
||||
"Smaller copies of block textures for distant terrain: less shimmer.": "Kleiner kopieë van blokteksture vir verafgeleë terrein: minder glans.",
|
||||
"Blends grass and water colours across biomes when building chunks.": "Vermeng gras en waterkleure oor biome wanneer stukke gebou word.",
|
||||
"Cloud layer: off, flat (fast) or 3D (fancy).": "Wolklaag: af, plat (vinnig) of 3D (fancy).",
|
||||
"How far clouds reach, in chunks.": "Hoe ver wolke reik, in stukke.",
|
||||
"Draws the sky, sun, moon and stars.": "Teken die lug, son, maan en sterre.",
|
||||
"Distance fog. Off shows the edge of the loaded world.": "Afstand mis. Af wys die rand van die gelaaide wêreld.",
|
||||
"Draws rain and snow.": "Trek reën en sneeu.",
|
||||
"How far rain and snow fall around you.": "Hoe ver val reën en sneeu om jou.",
|
||||
"How many particles effects spawn.": "Hoeveel deeltjies effekte kuit.",
|
||||
"Round shadows under mobs and items.": "Ronde skaduwees onder skares en items.",
|
||||
"Leaves with see-through gaps. Off draws them solid.": "Blare met deursigtige gapings. Off trek hulle stewig.",
|
||||
"Sorts water and glass more exactly behind each other.": "Sorteer water en glas meer presies agter mekaar.",
|
||||
"Which chunk rebuilds wait for the frame: none, nearby or yours.": "Watter stuk herbou wag vir die raam: geen, naby of joune.",
|
||||
"Animates water, lava, fire and other moving textures.": "Animeer water, lawa, vuur en ander bewegende teksture.",
|
||||
"World pixels per screen pixel. Below 100% is faster on the GPU.": "Wêreldpixels per skermpiksel. Onder 100% is vinniger op die GPU.",
|
||||
"Smooths jagged edges. FXAA: softer. TAA: smoothest, moving things may trail.": "Maak gekartelde rande glad. FXAA: sagter. TAA: gladste, bewegende dinge kan loop.",
|
||||
"Renders the world smaller and rebuilds it with TAA. Faster, softer.": "Maak die wêreld kleiner en herbou dit met TAA. Vinniger, sagter.",
|
||||
"HDR output on an HDR display: lava, fire and sunlight shine brighter.": "HDR-uitset op 'n HDR-skerm: lawa, vuur en sonlig skyn helderder.",
|
||||
"How frames reach the screen while VSync is off.": "Hoe rame die skerm bereik terwyl VSync af is.",
|
||||
"Efficient sleeps until the next frame; Precise spins, like vanilla.": "Doeltreffende slaap tot die volgende raam; Presiese draaie, soos vanielje.",
|
||||
"Fills the screen (borderless).": "Vul die skerm (randloos).",
|
||||
"Brightens dark places.": "Verhelder donker plekke.",
|
||||
"Lowers the frame rate when minimised, or idle too.": "Verlaag die raamtempo wanneer dit geminimaliseer word, of ook ledig.",
|
||||
"Sways the view while walking.": "Swaai die uitsig terwyl jy stap.",
|
||||
"Fades newly loaded chunks in.": "Vervaag nuutgelaaide stukke in.",
|
||||
"Darkens the screen's edges.": "Maak die skerm se rande donkerder.",
|
||||
"Shows when the world saves.": "Wys wanneer die wêreld red.",
|
||||
"Shows attack cooldown.": "Toon aanvalafkoeling.",
|
||||
"60 FPS cap (30 in menus or unfocused), half the workers: less power.": "60 FPS pet (30 in spyskaarte of ongefokus), die helfte van die werkers: minder krag.",
|
||||
"Threads that generate, light and mesh chunks. Next start.": "Drade wat stukke genereer, lig en maas. Volgende begin.",
|
||||
"Vulkan, then DirectX 12 (Windows) or OpenGL (Linux) where it fails. Next start.": "Vulkan, dan DirectX 12 (Windows) of OpenGL (Linux) waar dit misluk. Volgende begin.",
|
||||
"Water and glass in one buffer: fewer draw calls, a bit more VRAM. Next start.": "Water en glas in een buffer: minder trekoproepe, 'n bietjie meer VRAM. Volgende begin.",
|
||||
"Mesh data sent to the GPU per frame. Lower is smoother while loading.": "Maasdata per raam na die GPU gestuur. Laer is gladder tydens laai.",
|
||||
"Frame rate and frame times over the game, with a graph.": "Raamtempo en raamtye oor die spel, met 'n grafiek.",
|
||||
"horizon.multiplayer.finding_friend": "Soek jou vriend se wêreld...",
|
||||
"horizon.multiplayer.not_signed_in": "Hierdie bediener is in aanlynmodus. Meld aan met jou Microsoft-rekening in die Horizon-lanseerder om daarby aan te sluit.",
|
||||
"horizon.multiplayer.invalid_address": "Ongeldige bedieneradres: %s",
|
||||
"horizon.multiplayer.connected_friend_direct": "Reguit gekoppel aan jou vriend...",
|
||||
"horizon.multiplayer.connected_friend_relay": "Gekoppel aan jou vriend deur die aflos...",
|
||||
"General": "Algemeen",
|
||||
"Advanced": "Gevorderd",
|
||||
"Undo": "Ontdoen",
|
||||
"Search options": "Soek opsies",
|
||||
"Shortcut": "Kortpad",
|
||||
"Distance": "Afstand",
|
||||
"Display": "Vertoon",
|
||||
"Interface": "Koppelvlak",
|
||||
"Sky and weather": "Lug en weer",
|
||||
"Lighting and entities": "Beligting en entiteite",
|
||||
"Textures": "Teksture",
|
||||
"Image": "Beeld",
|
||||
"Chunk loading": "Chunk laai",
|
||||
"Culling": "Uitskot",
|
||||
"Power": "Krag",
|
||||
"Frames": "Rame",
|
||||
"Overlay": "Oorleg",
|
||||
"Output": "Uitset",
|
||||
"Brightness": "Helderheid",
|
||||
"How far you see, the window and the HUD.": "Hoe ver jy sien, die venster en die HUD.",
|
||||
"The sky and weather, lighting, textures and the image.": "Die lug en weer, beligting, teksture en die beeld.",
|
||||
"Chunk loading, culling and power use.": "Chunk laai, uitskot en kraggebruik.",
|
||||
"How frames reach the screen, and the performance overlay.": "Hoe rame die skerm bereik, en die prestasie-oorleg.",
|
||||
"Brighter-than-white output on an HDR display.": "Helderder-as-wit uitset op 'n HDR-skerm.",
|
||||
"Results for \"%s\"": "Resultate vir \"%s\"",
|
||||
"No settings match.": "Geen instellings pas nie.",
|
||||
"horizon.title.not_affiliated": "Nie geaffilieer met Mojang of Microsoft nie",
|
||||
"horizon.extras.header.lighting": "Beligting",
|
||||
"horizon.extras.header.third_person": "Derde persoon",
|
||||
"horizon.extras.header.particles": "Deeltjies",
|
||||
"horizon.extras.header.inventory": "Voorraad",
|
||||
"horizon.extras.header.chat": "Gesels",
|
||||
"horizon.extras.header.multiplayer": "Multispeler",
|
||||
"horizon.extras.header.sound": "Klank",
|
||||
"horizon.extras.header.menus": "Spyskaarte",
|
||||
"horizon.extras.fullbright": "Vol helder",
|
||||
"horizon.extras.dynamic_lights": "Dinamiese ligte",
|
||||
"horizon.extras.own_name_tag": "Eie naamplaatjie",
|
||||
"horizon.extras.hide_block_particles": "Versteek blokbreekdeeltjies",
|
||||
"horizon.extras.auto_reconnect": "Herkoppel outomaties",
|
||||
"horizon.extras.ui_sound_reserve": "Hou kanale vir UI-klanke",
|
||||
"horizon.extras.music_page": "Musiek bladsy",
|
||||
"horizon.extras.mouse_tweaks": "Muis Tweaks kontroles",
|
||||
"horizon.extras.mouse_tweaks_wheel": "Rolwiel beweeg items",
|
||||
"horizon.extras.sort": "Sorteer knoppies",
|
||||
"horizon.extras.sort_key": "Sorteer sleutel",
|
||||
"horizon.extras.no_ai": "Geen KI",
|
||||
"horizon.extras.agent_control": "Agent beheer",
|
||||
"horizon.extras.discord_presence": "Ryk teenwoordigheid op Discord",
|
||||
"horizon.extras.splitscreen": "Verdeelskerm",
|
||||
"horizon.extras.chat_animation": "Glad gesels",
|
||||
"horizon.extras.chat_indicator": "Boodskap aanwyser",
|
||||
"horizon.extras.wheel_cycles_settings": "Rolwiel verander instellings",
|
||||
"horizon.extras.pack_browser": "Hulpbronpakketblaaier",
|
||||
"horizon.extras.fullbright.tooltip": "Wys blokke en entiteite in volle lig, selfs in donker areas.",
|
||||
"horizon.extras.dynamic_lights.tooltip": "Fakkels en ander ligbronne wat vasgehou, laat val word of aan die brand steek, steek die blokke om hulle aan.",
|
||||
"horizon.extras.own_name_tag.tooltip": "Wys jou naam bo jou kop in derde persoon, soos ander spelers dit sien. Versteek wanneer die bediener jou span se name versteek of jy onsigbaar is.",
|
||||
"horizon.extras.hide_block_particles.tooltip": "Versteek die puindeeltjies wat uit 'n gebreekte blok bars en verkrummel van die een wat jy myn. Ander deeltjies bly.",
|
||||
"horizon.extras.auto_reconnect.tooltip": "Sluit weer by 'n bediener aan na 'n verlore verbinding of 'n herbegin, nooit na 'n skop of verbod nie.",
|
||||
"horizon.extras.ui_sound_reserve.tooltip": "Klanke in die wêreld laat 16 van die 247 klankkanale vry, so 'n vloed van hulle ('n groot ontploffing) kan nie kieslysklikke stilmaak nie.",
|
||||
"horizon.extras.music_page.tooltip": "Musiek en Klanke kry 'n Musiek...-bladsy: speel nou enige ingeboude snit, of skakel een af sodat die speletjie ophou om dit te kies. Niks verander totdat jy 'n snit afskakel nie.",
|
||||
"horizon.extras.mouse_tweaks.tooltip": "Regs-sleep plaas een per gleuf, links-sleep versamel die gehou item, Shift + links-sleep skuif elke gleuf.",
|
||||
"horizon.extras.mouse_tweaks_wheel.tooltip": "Af stuur een item van die gleuf na die ander kant, op bring een terug.",
|
||||
"horizon.extras.sort.tooltip": "Sorteer die voorraad, kiste, vate, eindkiste en shulkerbokse in kreatiewe oortjievolgorde, en voeg stapels saam.",
|
||||
"horizon.extras.sort_key.tooltip": "Sorteer die deel onder die wyser. Klik en druk dan 'n sleutel; Ontvlugting ontbind dit.",
|
||||
"horizon.extras.no_ai.tooltip": "Versteek en skakel elke KI-kenmerk af: agentbeheer, horizon-ctl en die MCP-bedieners. Die lanseerder se skakelaar ook.",
|
||||
"horizon.extras.agent_control.tooltip": "Jou eie KI-agent kan hierdie speletjie deur horizon-ctl of 'n MCP-kliënt speel, slegs op hierdie rekenaar.",
|
||||
"horizon.extras.discord_presence.tooltip": "Wys Playing Horizon op jou Discord-profiel terwyl Discord loop: spyskaarte, enkelspeler of multispeler, die dimensie en die speeltyd. Nooit 'n wêreld se naam of 'n bediener se adres nie.",
|
||||
"Calibrate...": "Kalibreer...",
|
||||
"Calibrate Anyway...": "Kalibreer in elk geval...",
|
||||
"Use Automatic Setup": "Gebruik outomatiese opstelling",
|
||||
"Shortcut: %s": "Kortpad: %s",
|
||||
"Next": "Volgende",
|
||||
"HDR Calibration %s/%s: %s": "HDR-kalibrasie %s/%s: %s",
|
||||
"Sets the three below full screen, one test picture at a time.": "Stel die drie hieronder volskerm, een toetsprent op 'n slag.",
|
||||
"A key that opens this screen from the game. Not bound at first.": "'n Sleutel wat hierdie skerm vanaf die speletjie oopmaak. Eers nie gebonde nie.",
|
||||
"Your display didn't say how bright it gets: calibrate to set it up.": "Jou skerm het nie gesê hoe helder dit word nie: kalibreer om dit op te stel.",
|
||||
"Already set up for your display. Only calibrate if HDR looks wrong.": "Reeds opgestel vir jou vertoning. Kalibreer slegs as HDR verkeerd lyk.",
|
||||
"Puts Peak Brightness and Paper White back to your display's setup.": "Plaas Peak Brightness en Paper White terug na jou skerm se opstelling.",
|
||||
"Set up for your display. Leave on Auto unless it looks wrong.": "Stel op vir jou vertoning. Los op Auto tensy dit verkeerd lyk.",
|
||||
"Lower it until the logo just disappears into the black.": "Laat sak dit totdat die logo net in die swart verdwyn.",
|
||||
"Raise it until the logo just disappears into the bright square.": "Lig dit op totdat die logo net in die helder vierkant verdwyn.",
|
||||
"Make the card a white that's comfortable to look at for a long time, in the light you play in.": "Maak die kaart 'n wit wat gemaklik is om lank na te kyk, in die lig waarin jy speel.",
|
||||
"horizon.splitscreen.profiles.forget": "Vergeet",
|
||||
"horizon.splitscreen.profiles.create": "Skep",
|
||||
"horizon.splitscreen.profiles.you": " - jy",
|
||||
"horizon.splitscreen.profiles.forget_named": "Vergeet %s",
|
||||
"horizon.splitscreen.profiles.previous": "Vorige",
|
||||
"horizon.splitscreen.profiles.next": "Volgende",
|
||||
"horizon.splitscreen.profiles.new_button": "Nuwe profiel...",
|
||||
"horizon.splitscreen.profiles.forget_title": "Vergeet profiel?",
|
||||
"horizon.splitscreen.profiles.forget_leaves": "Dit verlaat hierdie instansie se lys.",
|
||||
"horizon.splitscreen.profiles.forget_kept": "Wêreldvordering en instellings word behou.",
|
||||
"horizon.splitscreen.profiles.new_title": "Nuwe profiel",
|
||||
"horizon.splitscreen.profiles.name_hint": "Naam (3 tot 16 letters, syfers, _)",
|
||||
"horizon.splitscreen.profiles.switch_title": "Wissel profiel",
|
||||
"horizon.splitscreen.profiles.offline_note": "Vanlyn profiele behoort aan hierdie geval",
|
||||
"horizon.splitscreen.profiles.move": "Beweeg waar jy speel",
|
||||
"horizon.splitscreen.profiles.move_place": "Beweeg waar jy speel: %s",
|
||||
"horizon.friends.title": "Speel met vriende",
|
||||
"horizon.friends.hint": "Vriende plak die kode na die titelskerm se Vriende-knoppie, in Direkte verbinding, of op die lanseerder se Speel-bladsy.",
|
||||
"horizon.friends.copied": "Gekopieer",
|
||||
"horizon.friends.copy_code": "Kopieer kode",
|
||||
"horizon.friends.stop_sharing": "Hou op deel",
|
||||
"horizon.friends.none_yet": "Nog geen vriende hier nie.",
|
||||
"horizon.friends.here_now": "Hier nou: %s",
|
||||
"horizon.friends.share_intro": "Deel hierdie wêreld agter 'n uitnodigingskode: dit maak oop na LAN, en vriende op die internet sluit aan met die kode. Geen bediener van ons is betrokke nie.",
|
||||
"horizon.friends.start_sharing": "Begin deel",
|
||||
"horizon.friends.troubleshooting": "Foutsporing …",
|
||||
"horizon.friends.stopped": "Het opgehou om die uitnodigingkode te deel.",
|
||||
"horizon.friends.short_code_changed": "Iemand het aanhou om 'n verkeerde kort kode te probeer, so dit het verander.",
|
||||
"horizon.friends.wrong_code": "Iemand het 'n verkeerde kode probeer.",
|
||||
"horizon.friends.code_ready": "Jou uitnodigingskode is gereed: Speletjie-kieslys, Speel met vriende. Kopieer dit en stuur dit aan jou vriende.",
|
||||
"horizon.friends.share_failed": "Kon nie die wêreld deel nie: %s",
|
||||
"horizon.friends.finding_route": "Vind tans hoe vriende jou kan bereik …",
|
||||
"horizon.osk.shift": "Verskuiwing",
|
||||
"horizon.osk.space": "Ruimte",
|
||||
"horizon.osk.delete": "Vee uit",
|
||||
"horizon.osk.type": "Tik",
|
||||
"horizon.osk.symbols": "Simbole",
|
||||
"horizon.osk.close": "Maak toe",
|
||||
"horizon.extras.chat_animation.tooltip": "'n Nuwe kletslyn gly van links af terwyl dit vervaag, in plaas daarvan om heel te lyk.",
|
||||
"horizon.extras.chat_indicator.tooltip": "Die gekleurde balk aan die linkerkant van 'n kletslyn.",
|
||||
"horizon.extras.wheel_cycles_settings.tooltip": "Die rolwiel oor 'n knoppie in die instellings verander die waarde daarvan, soos in vanielje. Af, die wiel blaai net deur die lys.",
|
||||
"horizon.extras.pack_browser.tooltip": "Select Resource Packs kry 'n Voeg by-knoppie wat Modrinth deursoek en 'n pakket in jou pakke-lêergids installeer. Af, die speletjie kontak nooit Modrinth nie.",
|
||||
"horizon.extras.splitscreen.tooltip": "In 'n wêreld kan 'n ander beheerder as 'n nuwe speler aansluit: druk A wanneer dit vra, kies dan 'n profiel en waar om te speel.",
|
||||
"horizon.splitscreen.setup.monitor_unknown": "'n monitor",
|
||||
"horizon.splitscreen.setup.window": "Venster %s",
|
||||
"horizon.splitscreen.setup.new_window": "Nuwe venster",
|
||||
"horizon.splitscreen.setup.fill_monitor": "Vul %s",
|
||||
"horizon.splitscreen.setup.done": "Klaar",
|
||||
"horizon.splitscreen.setup.on": "Aan",
|
||||
"horizon.splitscreen.setup.off": "Af",
|
||||
"horizon.splitscreen.setup.player": "Speler %s",
|
||||
"horizon.splitscreen.setup.revert": "Keer terug",
|
||||
"horizon.splitscreen.setup.apply": "Doen aansoek",
|
||||
"horizon.splitscreen.setup.warning.empty_main": "Niemand speel in Venster 1 nie: dit skuil",
|
||||
"horizon.splitscreen.setup.warning.empty_close": "Niemand speel in Venster %s nie: dit sluit op Toepassing",
|
||||
"horizon.splitscreen.setup.warning.empty_new": "Niemand speel in Venster %s nie: dit sal nie oopmaak nie",
|
||||
"horizon.splitscreen.setup.warning.on_main": "Venster %s vul Venster 1 se monitor: sy spelers speel in Venster 1",
|
||||
"horizon.splitscreen.setup.warning.unplugged": "Venster %s se monitor is nie gekoppel nie: sy spelers speel in Venster 1",
|
||||
"horizon.splitscreen.setup.status.off": "Verdeelskerm is af.",
|
||||
"horizon.splitscreen.setup.status.enable_hint": "Skakel dit aan en druk dan 'n knoppie op 'n ander beheerder in 'n wêreld.",
|
||||
"horizon.splitscreen.setup.status.join_hint": "Druk A om aan te sluit en kies 'n profiel.",
|
||||
"horizon.splitscreen.setup.status.idle": "Gedeelskerm ledig",
|
||||
"horizon.splitscreen.setup.status.alone": "Geen ander plaaslike spelers nie.",
|
||||
"horizon.splitscreen.setup.status.solo_controls": "Solo-kontroles en kontroleerder-terugvoer is onveranderd.",
|
||||
"horizon.splitscreen.setup.window_empty": "Venster %s: leeg",
|
||||
"horizon.splitscreen.setup.note.select": "Klik 'n speler, of sleep dit na 'n venster of 'n monitor.",
|
||||
"horizon.splitscreen.setup.note.apply": "Doen aansoek om op hierdie manier te speel, Keer terug om te ontdoen.",
|
||||
"horizon.splitscreen.setup.note.place": "Waar moet %s speel?",
|
||||
"horizon.splitscreen.setup.this_player": "hierdie speler",
|
||||
"horizon.splitscreen.setup.switch_disabled": "Splitscreen skakel af sodra die ander vertrek het (hul pousekieslys).",
|
||||
"horizon.splitscreen.setup.window_place": "Venster %s (%s van %s)",
|
||||
"horizon.splitscreen.setup.names": "Name",
|
||||
"horizon.splitscreen.setup.identify": "Identifiseer",
|
||||
"horizon.splitscreen.setup.layout.two": "2 deel: %s",
|
||||
"horizon.splitscreen.setup.layout.three": "3 deel: %s",
|
||||
"horizon.splitscreen.setup.layout.two.0": "Outo",
|
||||
"horizon.splitscreen.setup.layout.two.1": "Sy aan sy",
|
||||
"horizon.splitscreen.setup.layout.two.2": "Bo en onder",
|
||||
"horizon.splitscreen.setup.layout.three.0": "Een breed bo-op",
|
||||
"horizon.splitscreen.setup.layout.three.1": "Een lang aan die linkerkant",
|
||||
"horizon.splitscreen.setup.layout.three.2": "Sy aan sy",
|
||||
"horizon.splitscreen.setup.help.player": "Klik of sleep %s om hulle te skuif.",
|
||||
"horizon.splitscreen.setup.help.layout_auto": "%s (naas mekaar wanneer die venster wyd is). Druk om te verander.",
|
||||
"horizon.splitscreen.setup.help.layout": "%s. Druk om te verander.",
|
||||
"horizon.splitscreen.setup.help.switch": "Verdeelskerm vir hierdie rekenaar, aan of af.",
|
||||
"horizon.splitscreen.setup.help.identify": "Elke speler se aansig wys in watter venster dit is.",
|
||||
"horizon.splitscreen.setup.help.names": "Elke speler se naam in die hoek van hul aansig.",
|
||||
"horizon.splitscreen.setup.help.revert": "Ontdoen die veranderinge wat nog nie toegepas is nie.",
|
||||
"horizon.splitscreen.setup.help.apply": "Speel soos die kaart wys.",
|
||||
"horizon.splitscreen.setup.help.unchanged": "Niks het nog verander nie.",
|
||||
"horizon.splitscreen.setup.give_up_pad": "Gee op Pad",
|
||||
"horizon.splitscreen.prompt.controller_connected": "Beheerder gekoppel",
|
||||
"horizon.splitscreen.prompt.controller_disconnected": "Beheerder ontkoppel",
|
||||
"horizon.splitscreen.prompt.controller_disconnected.hint": "Koppel dit weer, of druk 'n knoppie op 'n ander",
|
||||
"horizon.splitscreen.prompt.join.one": "%s wil aansluit",
|
||||
"horizon.splitscreen.prompt.join.many": "%s beheerders wil aansluit",
|
||||
"horizon.splitscreen.prompt.join.yes": "Sluit aan",
|
||||
"horizon.splitscreen.prompt.join.as_p1": "Speel as P1",
|
||||
"horizon.splitscreen.prompt.join.no": "Nee",
|
||||
"horizon.splitscreen.prompt.lost": "%s: beheerder ontkoppel",
|
||||
"horizon.splitscreen.prompt.lost.use_another": "Gebruik 'n ander",
|
||||
"horizon.splitscreen.prompt.lost.leave": "Los",
|
||||
"horizon.splitscreen.setup.help.give_up_pad": "Jou beheerder hou op om jou te bestuur en word aangebied om aan te sluit (A).",
|
||||
"horizon.splitscreen.setup.note.held_at": "%s tot %s: A laat val dit hier, B sit dit terug.",
|
||||
"horizon.splitscreen.setup.note.held": "%s opgetel: links/regs kies waar, A laat val, B sit dit terug.",
|
||||
"Hides models behind opaque blocks. Async checks off-thread; entities tick.": "Versteek modelle agter ondeursigtige blokke. Async kontroleer af-draad; entiteite merk.",
|
||||
"Block Entities": "Blok Entiteite",
|
||||
"Reuses settled boxes; lid movement stays animated.": "Hergebruik afgewikkelde bokse; dekselbeweging bly geanimeerd.",
|
||||
"Signs": "Tekens",
|
||||
"Reuses sign text until text, light, or font changes.": "Hergebruik tekenteks totdat teks, lig of lettertipe verander.",
|
||||
"Decorated Pots": "Versierde potte",
|
||||
"Reuses still pots; break wobble and sherd changes redraw.": "Hergebruik stilpotte; breek wankel en skeur veranderinge herteken.",
|
||||
"Bells": "Klokke",
|
||||
"Reuses still bells; ringing stays animated.": "Hergebruik stilstaande klokke; lui bly geanimeerd.",
|
||||
"Chests": "Kiste",
|
||||
"Reuses closed chests; moving lids stay animated.": "Hergebruik toe kiste; bewegende deksels bly geanimeerd.",
|
||||
"Banners": "Baniere",
|
||||
"Reuses poles; flags and pattern layers still update.": "Hergebruik pale; vlae en patroonlae werk steeds by.",
|
||||
"Copper Golem Statues": "Koper Golem-standbeelde",
|
||||
"Reuses statue geometry until its block state changes.": "Hergebruik standbeeldgeometrie totdat die bloktoestand daarvan verander.",
|
||||
"Leaf Culling": "Blaaruitsny",
|
||||
"Every leaf face. Vanilla's fancy leaves.": "Elke blaar gesig. Vanielje se spoggerige blare.",
|
||||
"Distant Plant Dither": "Verre Plant Dither",
|
||||
"Keeps fine plants in high-res packs from fading far away.": "Hou fyn plante in hoë-resolusie-pakke om ver weg te vervaag.",
|
||||
"Screenshot Quality": "Skermkiekie Kwaliteit",
|
||||
"F2 screenshots at this many times the game's resolution. Higher takes longer.": "F2 skermkiekies teen hierdie baie keer die spel se resolusie. Hoër neem langer.",
|
||||
"Frame Generation": "Raam Generasie",
|
||||
"Shows a made-up frame between each two real ones: smoother, a little more lag.": "Toon 'n opgemaakte raam tussen elke twee regte: gladder, 'n bietjie meer vertraging.",
|
||||
"Shadow Cache": "Skadu-kas",
|
||||
"Reuses the pack shadow map when sun, view and world match. Off by default.": "Hergebruik die pakskadukaart wanneer son, uitsig en wêreld ooreenstem. Af by verstek.",
|
||||
"Find BlueMap": "Vind BlueMap",
|
||||
"On servers, finds their BlueMap web map for far terrain. Next join.": "Op bedieners, vind hul BlueMap-webkaart vir ver terrein. Sluit volgende aan.",
|
||||
"BlueMap Radius": "Blou Kaart Radius",
|
||||
"How far around you BlueMap tiles are downloaded. Next join.": "Hoe ver om jou is BlueMap-teëls afgelaai. Sluit volgende aan.",
|
||||
"Synchronous": "Sinchronies",
|
||||
"Asynchronous": "Asinchronies",
|
||||
"Solid": "Solied",
|
||||
"Solid Aggressive": "Stewige aggressiewe",
|
||||
"Hollow": "Hol",
|
||||
"Leaves fully inside a canopy draw solid: fewer see-through layers.": "Blare volledig binne-in 'n blaredak trek solied: minder deurskynende lae.",
|
||||
"Leaves with one open side draw solid too: faster, chunkier edges.": "Blare met een oop kant trek ook solied: vinniger, bonkiger rande.",
|
||||
"Drops faces between leaves: faster, but gaps look through.": "Laat val gesigte tussen blare: vinniger, maar gapings kyk deur.",
|
||||
"Hotbar: Previous Slot": "Hotbar: Vorige Slot",
|
||||
"Hotbar: Next Slot": "Hotbar: Volgende Slot",
|
||||
"horizon.agent.connected.one": "Gekoppel: 1 agentverbinding",
|
||||
"horizon.agent.connected.many": "Gekoppel: %s agentverbindings",
|
||||
"horizon.agent.connected.one_ago": "Gekoppel: 1 agentverbinding, laaste opdrag %s s gelede",
|
||||
"horizon.agent.connected.many_ago": "Gekoppel: %s agentverbindings, laaste opdrag %s s gelede",
|
||||
"horizon.agent.waiting": "Wag vir 'n agent.",
|
||||
"horizon.agent.off": "Af: agente kan nie hierdie speletjie bereik nie.",
|
||||
"horizon.agent.session_opened": "Geopen vir hierdie sessie deur die program wat die speletjie begin het.",
|
||||
"horizon.agent.socket": "Sok: %s (kopieer die besonderhede vir sy volledige pad)",
|
||||
"horizon.agent.local_only": "Slegs plaaslik: agente op hierdie rekenaar, nooit die netwerk nie.",
|
||||
"%s nits": "%s nete",
|
||||
"Auto (%s nits)": "Outo (%s nete)",
|
||||
"%.2f nits": "%.2f nete",
|
||||
"Hides models behind opaque blocks. Entities update. Off with custom packs.": "Versteek modelle agter ondeursigtige blokke. Entiteite-opdatering. Af met pasgemaakte pakke.",
|
||||
"horizon.extras.repro_keys": "Opname kortpaaie",
|
||||
"horizon.extras.repro_keys.tooltip": "F3+R begin of stop 'n repro-opname en F3+E skryf sy bundel. Af by verstek: 'n opname kopieer die wêreld.",
|
||||
"horizon.agent.record_session": "Begin opnamesessie",
|
||||
"horizon.agent.record_stop": "Stop opnamesessie",
|
||||
"horizon.agent.export_repro": "Voer Repro-bundel uit",
|
||||
"horizon.repro.started": "Opname het begin; F3+R stop dit en skryf die bundel.",
|
||||
"horizon.repro.stopped": "Opname gestop: %s",
|
||||
"horizon.repro.bundle": "Repro-bundel: %s",
|
||||
"horizon.repro.no_recording": "Daar is nog geen opname om uit te voer nie.",
|
||||
"horizon.repro.replay_started": "Herhaling het begin: %s",
|
||||
"horizon.pack.addInfo": "Voeg 'n hulpbronpakket van Modrinth by",
|
||||
"horizon.pack.addWorking": "Vra vir Modrinth...",
|
||||
"horizon.pack.addNone": "Geen hulpbronpakke gevind nie",
|
||||
"horizon.pack.addTitle": "Voeg 'n hulpbronpakket by",
|
||||
"horizon.pack.install": "Installeer",
|
||||
"horizon.pack.installing": "Installeer tans",
|
||||
"horizon.pack.installed": "Geïnstalleer",
|
||||
"horizon.pack.search": "Soek",
|
||||
"horizon.pack.searchHint": "Soek Modrinth...",
|
||||
"horizon.pack.filter.realistic": "Realisties",
|
||||
"horizon.pack.filter.simplistic": "Simplistiese",
|
||||
"horizon.pack.filter.vanillaLike": "Vanielje-agtig",
|
||||
"horizon.pack.addFailed": "Die pakkie kon nie bygevoeg word nie: %s",
|
||||
"horizon.extras.header.cosmetics": "Skoonheidsmiddels",
|
||||
"horizon.extras.cosmetics_mine": "My skoonheidsmiddels",
|
||||
"horizon.extras.cosmetics_mine.tooltip": "Versteek: elke Horizon-speler sien jou sonder jou skoonheidsmiddels, jy ingesluit. Dieselfde skakelaar as die lanseerder se klerekas.",
|
||||
"horizon.extras.cosmetics_others": "Ander spelers se skoonheidsmiddels",
|
||||
"horizon.extras.cosmetics_others.tooltip": "Wat ander Horizon-spelers dra: alles, net hul naamplaatjiestyle, of niks. Versteek, die speletjie vra nooit wat hulle dra nie.",
|
||||
"horizon.extras.cosmetics_auras": "Ander se aura's en roetes",
|
||||
"horizon.extras.cosmetics_auras.tooltip": "Auras en roetes wat ander spelers dra. Af by verstek.",
|
||||
"horizon.extras.cosmetics.shown": "Getoon",
|
||||
"horizon.extras.cosmetics.hidden": "Versteek",
|
||||
"horizon.extras.cosmetics.name_tags": "Slegs naamplaatjies"
|
||||
}
|
||||
@@ -10,7 +10,6 @@
|
||||
"horizon.options.move_deadzone": "المنطقة الميتة للحركة",
|
||||
"horizon.options.look_deadzone": "المنطقة الميتة للنظر",
|
||||
"horizon.options.button_glyphs": "الحروف الرسومية للأزرار",
|
||||
"horizon.options.menu_navigation": "التنقل في القائمة",
|
||||
"horizon.options.on_screen_keyboard": "لوحة المفاتيح على الشاشة",
|
||||
"horizon.options.chat_delay": "تأخير الدردشة",
|
||||
"horizon.options.lightbar.health": "الصحة",
|
||||
@@ -19,8 +18,6 @@
|
||||
"horizon.options.glyphs.xbox": "اكس بوكس",
|
||||
"horizon.options.glyphs.playstation": "بلاي ستيشن",
|
||||
"horizon.options.glyphs.nintendo": "نينتندو",
|
||||
"horizon.options.menu_focus": "التركيز",
|
||||
"horizon.options.menu_pointer": "المؤشر",
|
||||
"horizon.options.keyboard.auto": "تلقائي",
|
||||
"horizon.options.keyboard.steam": "البخار",
|
||||
"horizon.options.unavailable": "هذه الميزة غير متوفرة بعد في Horizon.",
|
||||
|
||||
@@ -0,0 +1,470 @@
|
||||
{
|
||||
"horizon.options.controller": "Nəzarətçi",
|
||||
"horizon.options.vibration": "Vibrasiya",
|
||||
"horizon.options.adaptive_triggers": "Adaptiv tətiklər",
|
||||
"horizon.options.lightbar": "İşıq çubuğu",
|
||||
"horizon.options.look_sensitivity": "Baxış həssaslığı",
|
||||
"horizon.options.invert_x": "Tərs baxış X",
|
||||
"horizon.options.invert_y": "Tərs baxış Y",
|
||||
"horizon.options.sneak_button": "Gizlənmə düyməsi",
|
||||
"horizon.options.move_deadzone": "Hərəkət ölü zonası",
|
||||
"horizon.options.look_deadzone": "Baxış ölü zonası",
|
||||
"horizon.options.button_glyphs": "Düymə Qlifləri",
|
||||
"horizon.options.on_screen_keyboard": "Ekran Klaviaturası",
|
||||
"horizon.options.chat_delay": "Söhbət Gecikməsi",
|
||||
"horizon.options.lightbar.health": "Sağlamlıq",
|
||||
"horizon.options.lightbar.dimension": "Ölçü",
|
||||
"horizon.options.glyphs.auto": "Avtomatik",
|
||||
"horizon.options.keyboard.auto": "Avtomatik",
|
||||
"horizon.options.unavailable": "Bu funksiya hələ Horizon ərazisində mövcud deyil.",
|
||||
"horizon.options.search": "Axtarış parametrləri...",
|
||||
"horizon.pages.mods": "Modlar",
|
||||
"horizon.pages.shader_packs": "Shader Paketləri",
|
||||
"horizon.pages.shader_options": "Shader Seçimləri",
|
||||
"horizon.pages.controller": "Nəzarətçi Parametrləri",
|
||||
"horizon.pages.controller_binds": "Nəzarətçi Bağlayır",
|
||||
"horizon.pages.extras": "Horizon Əlavələr",
|
||||
"horizon.pages.settings": "Horizon Parametrlər",
|
||||
"horizon.pages.agent": "AI agenti",
|
||||
"horizon.split.leave": "tərk et",
|
||||
"horizon.pages.split_settings": "Splitscreen Parametrləri",
|
||||
"horizon.pages.split_profiles": "Kim oynayır?",
|
||||
"horizon.pages.split_setup": "Splitscreen Quraşdırma",
|
||||
"horizon.pages.music": "Musiqi",
|
||||
"horizon.pages.music.menu": "Menyu",
|
||||
"horizon.pages.music.overworld": "Yerüstü dünya",
|
||||
"horizon.pages.music.creative": "Yaradıcı",
|
||||
"horizon.pages.music.underwater": "Sualtı",
|
||||
"horizon.pages.music.end": "Son",
|
||||
"horizon.pages.music.boss": "patron",
|
||||
"horizon.pages.music.credits": "Kreditlər",
|
||||
"horizon.pages.music.overworld_biomes": "Yerüstü biomlar",
|
||||
"horizon.pages.music.nether_biomes": "Nether biomları",
|
||||
"horizon.pages.music.end_biomes": "Biomları bitir",
|
||||
"horizon.pages.music.other": "Digər musiqi",
|
||||
"horizon.pages.music.empty": "Musiqi parçaları yoxdur: oyunun səsləri yüklənmir.",
|
||||
"horizon.pages.music.tooltip": "Vəziyyətə görə quraşdırılmış treklər: birini indi oynayın və ya hər hansı birini söndürün ki, oyun onu seçməyi dayandırsın.",
|
||||
"horizon.pages.settings.tooltip": "Horizon öz parametrləri: qrafika, nəzarətçilər, əlavələr və modlar.",
|
||||
"horizon.pages.graphics.tooltip": "Qrafika, sadəcə olaraq: hər parametr nəyə başa gəldiyini bildirir.",
|
||||
"horizon.pages.graphics_advanced.tooltip": "Hər bir qrafik parametri, Horizon daxil edilir, hər birinin dəyəri ilə.",
|
||||
"horizon.pages.controller.tooltip": "Nəzarətçilər: onların düymələri, çubuqları, vibrasiya və menyu naviqasiyası.",
|
||||
"horizon.pages.extras.tooltip": "Könüllü əlavələr, hamısı defolt olaraq söndürülür: siz birini yandırana qədər oyun vanil olaraq qalır.",
|
||||
"horizon.pages.agent.tooltip": "Öz AI agentinizin oynamasına icazə verin: bu kompüterdə horizon-ctl və MCP müştəriləri.",
|
||||
"horizon.pages.split_profiles.tooltip": "Kim oynayır: bu oyun qovluğunda saxlanılan profil.",
|
||||
"horizon.pages.split_setup.tooltip": "Pəncərələr və monitorlar və kim harada oynayır.",
|
||||
"horizon.pages.shader_packs.tooltip": "shaderpacks qovluğundan şader paketləri: Horizon öz və shaders/formatında olanlar. Bir dəfə qaçır.",
|
||||
"horizon.pages.mods.tooltip": "Horizon-mods qovluğundan Horizon üçün hazırlanmış modlar. Hər biri sandboxda işləyir və siz onu yandırana qədər sönür.",
|
||||
"horizon.pages.open.graphics": "Qrafika...",
|
||||
"horizon.pages.open.graphics_advanced": "Qabaqcıl Qrafika...",
|
||||
"horizon.pages.open.shader_packs": "Shader Paketləri...",
|
||||
"horizon.pages.open.controller": "Nəzarətçi Parametrləri...",
|
||||
"horizon.pages.open.split_setup": "Ayrılmış ekran...",
|
||||
"horizon.pages.open.extras": "Əlavələr...",
|
||||
"horizon.pages.open.mods": "Modlar...",
|
||||
"horizon.pages.open.horizon_graphics": "Horizon Qrafika...",
|
||||
"horizon.pages.open.controller_binds": "Nəzarətçi Bağlayır...",
|
||||
"horizon.pages.open.horizon_settings": "Horizon Parametrlər...",
|
||||
"horizon.pages.open.music": "Musiqi...",
|
||||
"horizon.mods.empty": "Mod yoxdur: .hmod fayllarını horizon-mods qovluğuna qoyun",
|
||||
"horizon.mods.stopped": " (Dayandı)",
|
||||
"horizon.mods.not_built": " (tikilməyib)",
|
||||
"horizon.mods.settings": "Parametrlər",
|
||||
"horizon.mods.in_world": " (Dəyişmək üçün dünyanı tərk et)",
|
||||
"horizon.mods.open_folder": "Mod Qovluğunu açın",
|
||||
"horizon.shader_packs.empty": "Şeyder paketləri yoxdur: onları shaderpacks qovluğuna qoyun",
|
||||
"horizon.shader_options.open": "Shader Seçimləri...",
|
||||
"horizon.shader_options.profile": "Profil",
|
||||
"horizon.shader_options.loading": "Şeyder paketinin seçimləri oxunur...",
|
||||
"horizon.agent.copy_details": "Bağlantı təfərrüatlarını kopyalayın",
|
||||
"horizon.multiplayer.join": "Qoşulun",
|
||||
"horizon.multiplayer.cancel_reconnecting": "Yenidən qoşulmanı ləğv edin",
|
||||
"horizon.multiplayer.join_friend": "Dosta Qoşulun",
|
||||
"horizon.multiplayer.invite_code": "Dəvət Kodu",
|
||||
"horizon.multiplayer.relay": "Rele (isteğe bağlı)",
|
||||
"Preset": "Əvvəlcədən təyin",
|
||||
"LOD Distance": "LOD məsafəsi",
|
||||
"Far Detail": "Uzaq Detal",
|
||||
"Cave Culling": "Mağaraların kəsilməsi",
|
||||
"Entity Culling": "Müəssisə Culling",
|
||||
"Chunk Updates": "Parça Yeniləmələri",
|
||||
"Upload Budget": "Büdcə yükləyin",
|
||||
"Sky": "Göy",
|
||||
"Fog": "Duman",
|
||||
"Weather": "Hava",
|
||||
"Animated Textures": "Animasiyalı Dokular",
|
||||
"Present Mode": "İndiki rejim",
|
||||
"Worker Threads": "İşçi ipləri",
|
||||
"Resolution Scale": "Qətnamə Ölçüsü",
|
||||
"Upscaling": "Təkmilləşdirmə",
|
||||
"Paper White": "Kağız Ağ",
|
||||
"Peak Brightness": "Pik Parlaqlıq",
|
||||
"Black Level": "Qara Səviyyə",
|
||||
"UI Brightness": "UI Parlaqlığı",
|
||||
"Battery Mode": "Batareya rejimi",
|
||||
"Graphics API": "Qrafik API",
|
||||
"Translucent Batching": "Şəffaf Batching",
|
||||
"Performance Overlay": "Performans örtüyü",
|
||||
"Full Detail Distance": "Tam Detal Məsafə",
|
||||
"On": "Aktiv",
|
||||
"Off": "Söndür",
|
||||
"Unlimited": "Limitsiz",
|
||||
"Auto": "Avtomatik",
|
||||
"Custom": "Xüsusi",
|
||||
"Performance": "Performans",
|
||||
"Balanced": "Balanslı",
|
||||
"Quality": "Keyfiyyət",
|
||||
"Ultra Performance": "Ultra Performans",
|
||||
"Native": "Yerli",
|
||||
"Full": "Tam",
|
||||
"Reduced": "Azaldılmış",
|
||||
"Efficient": "Səmərəli",
|
||||
"Precise": "Dəqiq",
|
||||
"Auto (VSync)": "Avtomatik (VSync)",
|
||||
"FIFO": "FİFO",
|
||||
"Mailbox": "Poçt qutusu",
|
||||
"Immediate": "Dərhal",
|
||||
"FPS and Graph": "FPS və Qrafik",
|
||||
"No cost": "Xərc yoxdur",
|
||||
"Low cost": "Aşağı qiymət",
|
||||
"Medium cost": "Orta qiymət",
|
||||
"High cost": "Yüksək qiymət",
|
||||
"Saves time": "Vaxta qənaət edir",
|
||||
"Graphics": "Qrafika",
|
||||
"Done": "Bitdi",
|
||||
"This feature is not yet available in Horizon.": "Bu funksiya hələ Horizon ərazisində mövcud deyil.",
|
||||
"Your display or system doesn't offer HDR output.": "Ekranınız və ya sisteminiz HDR çıxışı təklif etmir.",
|
||||
"Turn HDR on to use it.": "İstifadə etmək üçün HDR-ni yandırın.",
|
||||
"Your GPU or graphics API doesn't support it.": "GPU və ya qrafik API onu dəstəkləmir.",
|
||||
"%s chunks": "%s parçalar",
|
||||
"%s per frame": "%s hər çərçivə üçün",
|
||||
"%s MiB/frame": "%s MiB/çərçivə",
|
||||
"%s KiB/frame": "%s KiB/çərçivə",
|
||||
"Auto (%s)": "Avtomatik (%s)",
|
||||
"Full-detail terrain range. LOD Distance can extend local worlds farther.": "Tam detallı ərazi diapazonu. LOD məsafəsi yerli dünyaları daha da uzada bilər.",
|
||||
"Coarse distant terrain in local worlds. Integrated GPUs stop at 128 chunks.": "Yerli dünyalarda kobud uzaq ərazi. İnteqrasiya edilmiş GPU-lar 128 hissədə dayanır.",
|
||||
"Reduced draws far terrain coarser: faster on this integrated GPU.": "Azaldılmış ərazini daha qaba çəkir: bu inteqrasiya olunmuş GPU-da daha sürətli.",
|
||||
"Reduced draws far terrain coarser, for GPUs it slows down.": "Azaldılmış ərazini daha qaba çəkir, GPU-lar üçün isə yavaşlayır.",
|
||||
"Field of view. Wider shows more terrain at once.": "Baxış sahəsi. Daha geniş bir anda daha çox ərazini göstərir.",
|
||||
"Caps frames per second; a cap saves power and heat.": "Saniyədə kadrların sayı; qapaq enerjiyə və istiliyə qənaət edir.",
|
||||
"Waits for the display's refresh: no tearing, a little latency.": "Ekranın təzələnməsini gözləyir: cırılma, bir az gecikmə.",
|
||||
"Size of menus and the HUD.": "Menyuların ölçüsü və HUD.",
|
||||
"Sets the options below together. Changing one makes it Custom.": "Aşağıdakı seçimləri birlikdə təyin edir. Birinin dəyişdirilməsi onu Xüsusi edir.",
|
||||
"Lava, fire and sunlight shine brighter than white. Needs an HDR display.": "Lava, od və günəş işığı ağdan daha parlaq parlayır. HDR displey lazımdır.",
|
||||
"Your display's darkest black. 0 for OLED; LCDs glow a little.": "Ekranınız ən tünd qaradır. OLED üçün 0; LCD-lər bir az parlayır.",
|
||||
"How bright highlights get. Auto: the peak your system reports.": "Parlaq məqamlar necə əldə edilir. Avtomatik: sisteminizin ən yüksək hesabatı.",
|
||||
"How bright white paper and menus look. Auto: your desktop's white.": "Ağ kağız və menyular necə parlaq görünür. Avtomatik: masaüstünüz ağ rəngdədir.",
|
||||
"How bright the HUD and menus are, against paper white.": "HUD və menyular ağ kağıza qarşı nə qədər parlaqdır.",
|
||||
"How far mobs, crops and machines keep working. CPU time.": "Kütlələr, məhsullar və maşınlar nə qədər işləməyə davam edir. CPU vaxtı.",
|
||||
"How far away mobs and items are drawn, as a share of normal.": "Nə qədər uzağa mob və əşyalar çəkilir, normal bir pay olaraq.",
|
||||
"Skips terrain hidden behind closed sections. Off costs a lot.": "Qapalı hissələrin arxasında gizlənmiş ərazini ötür. Sıxılma çox baha başa gəlir.",
|
||||
"Hides entities behind opaque blocks.": "Obyektləri qeyri-şəffaf blokların arxasında gizlədir.",
|
||||
"No entity occlusion culling.": "Heç bir obyektin okklyuziyası məhv edilmir.",
|
||||
"CPU occlusion test runs this frame.": "CPU tıxanma testi bu çərçivəni idarə edir.",
|
||||
"Occlusion checks run on a worker thread.": "Tıxanma yoxlanışı işçi ipində aparılır.",
|
||||
"Meshed sections uploaded per frame. Lower is smoother while loading.": "Meshed bölmələr hər çərçivəyə yüklənir. Yükləyərkən aşağı daha hamar olur.",
|
||||
"Soft shadows in corners. Costs chunk building time only.": "Künclərdə yumşaq kölgələr. Yalnız tikinti vaxtı xərcləri.",
|
||||
"Smaller copies of block textures for distant terrain: less shimmer.": "Uzaq ərazilər üçün blok dokuların daha kiçik nüsxələri: daha az parıltı.",
|
||||
"Blends grass and water colours across biomes when building chunks.": "Parçalar qurarkən biomlar arasında ot və su rənglərini qarışdırır.",
|
||||
"Cloud layer: off, flat (fast) or 3D (fancy).": "Bulud təbəqəsi: sönük, düz (sürətli) və ya 3D (fantastik).",
|
||||
"How far clouds reach, in chunks.": "Buludlar nə qədər uzağa çatır, parça-parça.",
|
||||
"Draws the sky, sun, moon and stars.": "Göyü, günəşi, ayı və ulduzları çəkir.",
|
||||
"Distance fog. Off shows the edge of the loaded world.": "Məsafə dumanı. Off yüklənmiş dünyanın kənarını göstərir.",
|
||||
"Draws rain and snow.": "Yağış və qar çəkir.",
|
||||
"How far rain and snow fall around you.": "Ətrafınıza yağış və qar nə qədər yağır.",
|
||||
"How many particles effects spawn.": "Nə qədər hissəcik effektləri kürü verir.",
|
||||
"Round shadows under mobs and items.": "Kütlələrin və əşyaların altında dairəvi kölgələr.",
|
||||
"Leaves with see-through gaps. Off draws them solid.": "Yarpaqları göz qabağındadır. Off onları möhkəm çəkir.",
|
||||
"Sorts water and glass more exactly behind each other.": "Suyu və şüşəni bir-birinin arxasında daha dəqiq şəkildə sıralayır.",
|
||||
"Which chunk rebuilds wait for the frame: none, nearby or yours.": "Hansı hissənin yenidən qurulması çərçivəni gözləyir: heç biri, yaxınlıqda və ya sizin.",
|
||||
"Animates water, lava, fire and other moving textures.": "Su, lava, od və digər hərəkətli dokuları canlandırır.",
|
||||
"Smooths jagged edges. FXAA: softer. TAA: smoothest, moving things may trail.": "Kəsik kənarları hamarlayır. FXAA: daha yumşaq. TAA: ən hamar, hərəkətli şeylər cığır çəkə bilər.",
|
||||
"Renders the world smaller and rebuilds it with TAA. Faster, softer.": "Dünyanı daha kiçik edir və TAA ilə yenidən qurur. Daha sürətli, daha yumşaq.",
|
||||
"HDR output on an HDR display: lava, fire and sunlight shine brighter.": "HDR displeydə HDR çıxışı: lava, yanğın və günəş işığı daha parlaq parlayır.",
|
||||
"How frames reach the screen while VSync is off.": "VSync söndürüldükdə çərçivələr ekrana necə çatır.",
|
||||
"Efficient sleeps until the next frame; Precise spins, like vanilla.": "Növbəti kadra qədər səmərəli yuxular; Vanil kimi dəqiq spinlər.",
|
||||
"Fills the screen (borderless).": "Ekranı doldurur (sərhədsiz).",
|
||||
"Brightens dark places.": "Qaranlıq yerləri işıqlandırır.",
|
||||
"Lowers the frame rate when minimised, or idle too.": "Minimumlaşdırıldıqda və ya boş olduqda kadr sürətini azaldır.",
|
||||
"Sways the view while walking.": "Gəzərkən mənzərəni yelləyir.",
|
||||
"Fades newly loaded chunks in.": "Yeni yüklənmiş parçaları sönür.",
|
||||
"Darkens the screen's edges.": "Ekranın kənarlarını qaraldır.",
|
||||
"Shows when the world saves.": "Dünyanın nə vaxt xilas etdiyini göstərir.",
|
||||
"Shows attack cooldown.": "Hücumun soyumasını göstərir.",
|
||||
"60 FPS cap (30 in menus or unfocused), half the workers: less power.": "60 FPS qapağı (menyularda 30 və ya diqqətsiz), işçilərin yarısı: daha az güc.",
|
||||
"Threads that generate, light and mesh chunks. Next start.": "Yaradan iplər, yüngül və mesh parçaları. Növbəti başlanğıc.",
|
||||
"Vulkan, then DirectX 12 (Windows) or OpenGL (Linux) where it fails. Next start.": "Vulkan, sonra uğursuz olduğu DirectX 12 (Windows) və ya OpenGL (Linux). Növbəti başlanğıc.",
|
||||
"Water and glass in one buffer: fewer draw calls, a bit more VRAM. Next start.": "Bir buferdə su və şüşə: daha az çəkiliş zəngi, bir az daha çox VRAM. Növbəti başlanğıc.",
|
||||
"Mesh data sent to the GPU per frame. Lower is smoother while loading.": "Hər kadra GPU-ya göndərilən mesh datası. Yükləyərkən aşağı daha hamar olur.",
|
||||
"Frame rate and frame times over the game, with a graph.": "Qrafik ilə oyun üzrə çərçivə sürəti və kadr vaxtları.",
|
||||
"horizon.multiplayer.finding_friend": "Dostunuzun dünyasını tapmaq...",
|
||||
"horizon.multiplayer.not_signed_in": "Bu server onlayn rejimdədir. Qoşulmaq üçün Horizon başlatma cihazında Microsoft hesabınızla daxil olun.",
|
||||
"horizon.multiplayer.invalid_address": "Yanlış server ünvanı: %s",
|
||||
"horizon.multiplayer.connected_friend_direct": "Dostunuza birbaşa qoşulun...",
|
||||
"horizon.multiplayer.connected_friend_relay": "Rele vasitəsilə dostunuza qoşulun...",
|
||||
"Advanced": "Qabaqcıl",
|
||||
"Undo": "Geri alın",
|
||||
"Search options": "Axtarış seçimləri",
|
||||
"Shortcut": "Qısayol",
|
||||
"Distance": "Məsafə",
|
||||
"Display": "Ekran",
|
||||
"Interface": "İnterfeys",
|
||||
"Sky and weather": "Səma və hava",
|
||||
"Lighting and entities": "İşıqlandırma və obyektlər",
|
||||
"Textures": "Dokular",
|
||||
"Image": "Şəkil",
|
||||
"Chunk loading": "Parça yükləmə",
|
||||
"Power": "Güc",
|
||||
"Frames": "Çərçivələr",
|
||||
"Output": "Çıxış",
|
||||
"Brightness": "Parlaqlıq",
|
||||
"How far you see, the window and the HUD.": "Nə qədər görürsən, pəncərə və HUD.",
|
||||
"The sky and weather, lighting, textures and the image.": "Səma və hava, işıqlandırma, faktura və görüntü.",
|
||||
"Chunk loading, culling and power use.": "Parçaların yüklənməsi, kəsilməsi və enerji istifadəsi.",
|
||||
"How frames reach the screen, and the performance overlay.": "Çərçivələrin ekrana necə çatması və performans örtüyü.",
|
||||
"Brighter-than-white output on an HDR display.": "HDR displeydə ağdan daha parlaq çıxış.",
|
||||
"Results for \"%s\"": "\"%s\" üçün nəticələr",
|
||||
"No settings match.": "Heç bir parametr uyğun gəlmir.",
|
||||
"horizon.title.not_affiliated": "Mojang və ya Microsoft ilə əlaqəli deyil",
|
||||
"horizon.extras.header.lighting": "İşıqlandırma",
|
||||
"horizon.extras.header.third_person": "Üçüncü şəxs",
|
||||
"horizon.extras.header.particles": "hissəciklər",
|
||||
"horizon.extras.header.inventory": "İnventar",
|
||||
"horizon.extras.header.chat": "Söhbət",
|
||||
"horizon.extras.header.sound": "Səs",
|
||||
"horizon.extras.header.menus": "Menyular",
|
||||
"horizon.extras.fullbright": "Tam parlaq",
|
||||
"horizon.extras.dynamic_lights": "Dinamik işıqlar",
|
||||
"horizon.extras.own_name_tag": "Öz ad etiketi",
|
||||
"horizon.extras.hide_block_particles": "Blok qırılan hissəcikləri gizlədin",
|
||||
"horizon.extras.auto_reconnect": "Avtomatik yenidən qoşulun",
|
||||
"horizon.extras.ui_sound_reserve": "UI səsləri üçün kanalları saxlayın",
|
||||
"horizon.extras.music_page": "Musiqi səhifəsi",
|
||||
"horizon.extras.mouse_tweaks": "Mouse Tweaks nəzarətləri",
|
||||
"horizon.extras.mouse_tweaks_wheel": "Sürüşdürmə çarxı elementləri hərəkət etdirir",
|
||||
"horizon.extras.sort": "Çeşidləmə düymələri",
|
||||
"horizon.extras.sort_key": "Sıralama açarı",
|
||||
"horizon.extras.no_ai": "AI yoxdur",
|
||||
"horizon.extras.agent_control": "Agent Nəzarəti",
|
||||
"horizon.extras.chat_animation": "Rahat söhbət",
|
||||
"horizon.extras.chat_indicator": "Mesaj göstəricisi",
|
||||
"horizon.extras.wheel_cycles_settings": "Sürüşdürmə çarxı parametrləri dəyişir",
|
||||
"horizon.extras.pack_browser": "Resurs paketi brauzeri",
|
||||
"horizon.extras.fullbright.tooltip": "Blokları və obyektləri hətta qaranlıq yerlərdə də tam işıqda göstərin.",
|
||||
"horizon.extras.dynamic_lights.tooltip": "Məşəllər və digər işıq mənbələri ətrafdakı blokları tutmuş, yerə atmış və ya odda yandırır.",
|
||||
"horizon.extras.own_name_tag.tooltip": "Başqa oyunçuların gördüyü kimi adınızı başınızın üstündə üçüncü şəxsdə göstərir. Server komandanızın adlarını gizlətdikdə və ya siz görünməz olduğunuzda gizlidir.",
|
||||
"horizon.extras.hide_block_particles.tooltip": "Sınıq blokdan qopan və mənimsədiyiniz blokdan parçalanan zibil hissəciklərini gizlədir. Digər hissəciklər qalır.",
|
||||
"horizon.extras.auto_reconnect.tooltip": "Heç bir zərbə və ya qadağadan sonra itən əlaqə və ya yenidən başladıqdan sonra serverə yenidən qoşulur.",
|
||||
"horizon.extras.ui_sound_reserve.tooltip": "Dünyadakı səslər 247 səs kanalından 16-nı pulsuz buraxır, buna görə də onların selinin (böyük partlayış) menyu kliklərini susdura bilməz.",
|
||||
"horizon.extras.music_page.tooltip": "Musiqi və Səslər Musiqi... səhifəsi əldə edir: hər hansı daxili treki indi çalın və ya birini söndürün ki, oyun onu seçməyi dayandırsın. Siz treki söndürməyincə heç nə dəyişməyəcək.",
|
||||
"horizon.extras.mouse_tweaks.tooltip": "Sağa sürükləmək hər yuvaya bir yerləşdirir, sola sürükləmək saxlanılan elementi toplayır, Shift + sola sürükləmək hər bir yuvaya köçür.",
|
||||
"horizon.extras.mouse_tweaks_wheel.tooltip": "Aşağı yuvanın bir elementini digər tərəfə göndərir, yuxarı birini geri gətirir.",
|
||||
"horizon.extras.sort.tooltip": "İnventar, sandıqlar, çəlləklər, ender sandıqlar və şulker qutularını yaradıcı nişan sırası ilə çeşidləyir, yığınları birləşdirin.",
|
||||
"horizon.extras.sort_key.tooltip": "Kursorun altındakı hissəni çeşidləyir. Basın, sonra düyməni basın; Escape onu açır.",
|
||||
"horizon.extras.no_ai.tooltip": "Hər bir AI funksiyasını gizlədir və söndürür: agent nəzarəti, horizon-ctl və MCP serverləri. Başlatıcının açarı da.",
|
||||
"horizon.extras.agent_control.tooltip": "Öz AI agentiniz bu oyunu horizon-ctl və ya MCP müştəri vasitəsilə yalnız bu kompüterdə oynaya bilər.",
|
||||
"horizon.extras.discord_presence.tooltip": "Discord işləyərkən Discord profilinizdə Horizon Playing göstərilir: menyular, tək oyunçu və ya multiplayer, ölçü və oynanılan vaxt. Heç vaxt dünyanın adı və ya server ünvanı.",
|
||||
"Calibrate...": "Kalibrləmə...",
|
||||
"Calibrate Anyway...": "İstənilən halda kalibrləyin...",
|
||||
"Use Automatic Setup": "Avtomatik Quraşdırmadan istifadə edin",
|
||||
"Shortcut: %s": "Qısayol: %s",
|
||||
"Next": "Sonrakı",
|
||||
"HDR Calibration %s/%s: %s": "HDR Kalibrləmə %s/%s: %s",
|
||||
"Sets the three below full screen, one test picture at a time.": "Aşağıdakı üç tam ekranı, hər dəfə bir sınaq şəklini təyin edir.",
|
||||
"A key that opens this screen from the game. Not bound at first.": "Oyundan bu ekranı açan açar. Əvvəlcə bağlı deyil.",
|
||||
"Your display didn't say how bright it gets: calibrate to set it up.": "Ekranınız nə qədər parlaq olduğunu deməyib: onu qurmaq üçün kalibrləyin.",
|
||||
"Already set up for your display. Only calibrate if HDR looks wrong.": "Ekranınız üçün artıq qurulub. Yalnız HDR səhv görünürsə kalibrləyin.",
|
||||
"Puts Peak Brightness and Paper White back to your display's setup.": "Pik Parlaqlığı və Kağız Ağı ekranınızın quraşdırılmasına qaytarır.",
|
||||
"Set up for your display. Leave on Auto unless it looks wrong.": "Ekranınız üçün qurun. Səhv görünməsə, Auto-da buraxın.",
|
||||
"Lower it until the logo just disappears into the black.": "Loqo qara rəngdə yox olana qədər onu endirin.",
|
||||
"Raise it until the logo just disappears into the bright square.": "Loqo parlaq kvadratda yox olana qədər onu qaldırın.",
|
||||
"Make the card a white that's comfortable to look at for a long time, in the light you play in.": "Kartı oynadığınız işıqda uzun müddət baxmaq üçün rahat olan ağ rəngə çevirin.",
|
||||
"horizon.splitscreen.profiles.forget": "Unut",
|
||||
"horizon.splitscreen.profiles.create": "Yaradın",
|
||||
"horizon.splitscreen.profiles.you": " - sən",
|
||||
"horizon.splitscreen.profiles.forget_named": "Unut %s",
|
||||
"horizon.splitscreen.profiles.previous": "Əvvəlki",
|
||||
"horizon.splitscreen.profiles.next": "Sonrakı",
|
||||
"horizon.splitscreen.profiles.new_button": "Yeni Profil...",
|
||||
"horizon.splitscreen.profiles.forget_title": "Profili unutmusunuz?",
|
||||
"horizon.splitscreen.profiles.forget_leaves": "Bu nümunənin siyahısını tərk edir.",
|
||||
"horizon.splitscreen.profiles.forget_kept": "Dünya tərəqqisi və parametrlər saxlanılır.",
|
||||
"horizon.splitscreen.profiles.new_title": "Yeni Profil",
|
||||
"horizon.splitscreen.profiles.name_hint": "Ad (3-16 hərf, rəqəm, _)",
|
||||
"horizon.splitscreen.profiles.switch_title": "Profilə keçin",
|
||||
"horizon.splitscreen.profiles.offline_note": "Oflayn profillər bu instansiyaya aiddir",
|
||||
"horizon.splitscreen.profiles.move": "Oynadığınız yerdə hərəkət edin",
|
||||
"horizon.splitscreen.profiles.move_place": "Oynadığınız yerə köçürün: %s",
|
||||
"horizon.friends.title": "Dostlarla oynayın",
|
||||
"horizon.friends.hint": "Dostlar kodu başlıq ekranının Dostlar düyməsindən sonra, Birbaşa Bağlantıda və ya başlatma qurğusunun Play səhifəsində yerləşdirin.",
|
||||
"horizon.friends.copied": "Kopyalandı",
|
||||
"horizon.friends.copy_code": "Kodu kopyalayın",
|
||||
"horizon.friends.stop_sharing": "Paylaşmağı dayandırın",
|
||||
"horizon.friends.none_yet": "Burada hələ dost yoxdur.",
|
||||
"horizon.friends.here_now": "İndi burada: %s",
|
||||
"horizon.friends.share_intro": "Bu dünyanı dəvət kodunun arxasında paylaşın: o, LAN-a açılır və internetdəki dostlar kodla qoşulur. Heç bir serverimiz iştirak etmir.",
|
||||
"horizon.friends.start_sharing": "Paylaşmağa başlayın",
|
||||
"horizon.friends.troubleshooting": "Problem həll olunur...",
|
||||
"horizon.friends.stopped": "Dəvət kodunu paylaşmağı dayandırdı.",
|
||||
"horizon.friends.short_code_changed": "Kimsə səhv qısa kodu sınamağa davam etdi, ona görə də dəyişdi.",
|
||||
"horizon.friends.wrong_code": "Kimsə səhv kodu sınadı.",
|
||||
"horizon.friends.code_ready": "Dəvət kodunuz hazırdır: Oyun Menyu, Dostlarla Oyna. Kopyalayın və dostlarınıza göndərin.",
|
||||
"horizon.friends.share_failed": "Dünyanı paylaşmaq mümkün olmadı: %s",
|
||||
"horizon.friends.finding_route": "Dostların sizinlə necə əlaqə saxlaya biləcəyi tapılır...",
|
||||
"horizon.osk.space": "Kosmos",
|
||||
"horizon.osk.delete": "Sil",
|
||||
"horizon.osk.type": "Növ",
|
||||
"horizon.osk.symbols": "Simvollar",
|
||||
"horizon.osk.close": "Bağlayın",
|
||||
"horizon.extras.chat_animation.tooltip": "Yeni söhbət xətti bütöv görünmək əvəzinə soldan içəri sürüşür.",
|
||||
"horizon.extras.chat_indicator.tooltip": "Söhbət xəttinin solunda olan rəngli bar.",
|
||||
"horizon.extras.wheel_cycles_settings.tooltip": "Parametrlərdəki düymənin üzərindəki sürüşdürmə çarxı vanildə olduğu kimi dəyərini dəyişir. Söndürülmüş, təkər yalnız siyahını sürüşdürür.",
|
||||
"horizon.extras.pack_browser.tooltip": "Resurs Paketlərini seçin Modrinth-də axtarış aparan və paketlər qovluğuna paket quraşdıran Əlavə et düyməsini alır. Off, oyun Modrinthlə heç vaxt əlaqə saxlamır.",
|
||||
"horizon.extras.splitscreen.tooltip": "Dünyada başqa bir nəzarətçi yeni oyunçu kimi qoşula bilər: soruşduqda A düyməsini basın, sonra profil və harada oynayacağınızı seçin.",
|
||||
"horizon.splitscreen.setup.monitor_unknown": "monitor",
|
||||
"horizon.splitscreen.setup.window": "Pəncərə %s",
|
||||
"horizon.splitscreen.setup.new_window": "Yeni pəncərə",
|
||||
"horizon.splitscreen.setup.fill_monitor": "%s doldurun",
|
||||
"horizon.splitscreen.setup.done": "Bitdi",
|
||||
"horizon.splitscreen.setup.on": "Aktiv",
|
||||
"horizon.splitscreen.setup.off": "Söndür",
|
||||
"horizon.splitscreen.setup.player": "Oyunçu %s",
|
||||
"horizon.splitscreen.setup.revert": "Geri qaytarın",
|
||||
"horizon.splitscreen.setup.apply": "Müraciət edin",
|
||||
"horizon.splitscreen.setup.warning.empty_main": "Window 1-də heç kim oynamır: gizlənir",
|
||||
"horizon.splitscreen.setup.warning.empty_close": "%s Pəncərəsində heç kim oynamır: Tətbiq edərkən bağlanır",
|
||||
"horizon.splitscreen.setup.warning.empty_new": "%s pəncərəsində heç kim oynamır: açılmayacaq",
|
||||
"horizon.splitscreen.setup.warning.on_main": "Pəncərə %s Pəncərə 1-in monitorunu doldurur: onun oyunçuları Pəncərə 1-də oynayır",
|
||||
"horizon.splitscreen.setup.warning.unplugged": "Pəncərənin %s monitoru bağlı deyil: onun oyunçuları Window 1-də oynayır",
|
||||
"horizon.splitscreen.setup.status.off": "Splitscreen deaktivdir.",
|
||||
"horizon.splitscreen.setup.status.enable_hint": "Onu yandırın, sonra dünyanın başqa bir nəzarətçisində düyməni basın.",
|
||||
"horizon.splitscreen.setup.status.join_hint": "Qoşulmaq və profil seçmək üçün A düyməsini basın.",
|
||||
"horizon.splitscreen.setup.status.idle": "Splitscreen boş",
|
||||
"horizon.splitscreen.setup.status.alone": "Başqa yerli oyunçu yoxdur.",
|
||||
"horizon.splitscreen.setup.status.solo_controls": "Solo nəzarət və nəzarətçi rəyi dəyişməzdir.",
|
||||
"horizon.splitscreen.setup.window_empty": "Pəncərə %s: boş",
|
||||
"horizon.splitscreen.setup.note.select": "Oyunçuya klikləyin və ya onu pəncərəyə və ya monitora sürükləyin.",
|
||||
"horizon.splitscreen.setup.note.apply": "Bu şəkildə oynamaq üçün müraciət edin, ləğv etmək üçün geri qaytarın.",
|
||||
"horizon.splitscreen.setup.note.place": "%s harada oynamalıdır?",
|
||||
"horizon.splitscreen.setup.this_player": "bu oyunçu",
|
||||
"horizon.splitscreen.setup.switch_disabled": "Digərləri ayrıldıqdan sonra Splitscreen sönür (pauza menyusu).",
|
||||
"horizon.splitscreen.setup.window_place": "Pəncərə %s (%s/%s)",
|
||||
"horizon.splitscreen.setup.names": "Adlar",
|
||||
"horizon.splitscreen.setup.identify": "Müəyyən etmək",
|
||||
"horizon.splitscreen.setup.layout.two": "2 paylaşım: %s",
|
||||
"horizon.splitscreen.setup.layout.three": "3 paylaşım: %s",
|
||||
"horizon.splitscreen.setup.layout.two.0": "Avtomatik",
|
||||
"horizon.splitscreen.setup.layout.two.1": "Yan-yana",
|
||||
"horizon.splitscreen.setup.layout.two.2": "Üst və alt",
|
||||
"horizon.splitscreen.setup.layout.three.0": "Üstündə biri geniş",
|
||||
"horizon.splitscreen.setup.layout.three.1": "Solda biri hündür",
|
||||
"horizon.splitscreen.setup.layout.three.2": "Yan-yana",
|
||||
"horizon.splitscreen.setup.help.player": "Onları köçürmək üçün %s üzərinə klikləyin və ya dartın.",
|
||||
"horizon.splitscreen.setup.help.layout_auto": "%s (pəncərə geniş olduqda yan-yana). Dəyişmək üçün basın.",
|
||||
"horizon.splitscreen.setup.help.layout": "%s. Dəyişmək üçün basın.",
|
||||
"horizon.splitscreen.setup.help.switch": "Bu kompüter üçün bölünmüş ekran, aktiv və ya söndürülür.",
|
||||
"horizon.splitscreen.setup.help.identify": "Hər bir oyunçunun görünüşü onun hansı pəncərədə olduğunu göstərir.",
|
||||
"horizon.splitscreen.setup.help.names": "Görünüşünün küncündə hər bir oyunçunun adı.",
|
||||
"horizon.splitscreen.setup.help.revert": "Hələ tətbiq olunmamış dəyişiklikləri geri alın.",
|
||||
"horizon.splitscreen.setup.help.apply": "Xəritənin göstərdiyi şəkildə oynayın.",
|
||||
"horizon.splitscreen.setup.help.unchanged": "Hələ heç nə dəyişməyib.",
|
||||
"horizon.splitscreen.setup.give_up_pad": "Pasxadan imtina et",
|
||||
"horizon.splitscreen.prompt.controller_connected": "Nəzarətçi qoşulub",
|
||||
"horizon.splitscreen.prompt.controller_disconnected": "Nəzarətçi ayrıldı",
|
||||
"horizon.splitscreen.prompt.controller_disconnected.hint": "Onu yenidən birləşdirin və ya digərində düyməni basın",
|
||||
"horizon.splitscreen.prompt.join.one": "%s qoşulmaq istəyir",
|
||||
"horizon.splitscreen.prompt.join.many": "%s nəzarətçilər qoşulmaq istəyirlər",
|
||||
"horizon.splitscreen.prompt.join.yes": "Qoşulun",
|
||||
"horizon.splitscreen.prompt.join.as_p1": "P1 kimi oynayın",
|
||||
"horizon.splitscreen.prompt.join.no": "yox",
|
||||
"horizon.splitscreen.prompt.lost": "%s: nəzarətçi ayrıldı",
|
||||
"horizon.splitscreen.prompt.lost.use_another": "Başqasını istifadə edin",
|
||||
"horizon.splitscreen.prompt.lost.leave": "tərk et",
|
||||
"horizon.splitscreen.setup.help.give_up_pad": "Nəzarətçiniz sizi idarə etməyi dayandırır və ona qoşulmaq təklif olunur (A).",
|
||||
"horizon.splitscreen.setup.note.held_at": "%s to %s: A onu bura düşür, B onu geri qoyur.",
|
||||
"horizon.splitscreen.setup.note.held": "%s götürdü: sol/sağ yeri seçir, A düşür, B onu geri qoyur.",
|
||||
"Hides models behind opaque blocks. Async checks off-thread; entities tick.": "Modelləri qeyri-şəffaf blokların arxasında gizlədir. Async-dən kənar yoxlayır; qurumlar işarələyir.",
|
||||
"Block Entities": "Blok obyektləri",
|
||||
"Shulker Boxes": "Shulker qutuları",
|
||||
"Reuses settled boxes; lid movement stays animated.": "Yerləşmiş qutuları təkrar istifadə edir; qapaq hərəkəti canlı qalır.",
|
||||
"Signs": "İşarələr",
|
||||
"Reuses sign text until text, light, or font changes.": "Mətn, işıq və ya şrift dəyişənə qədər işarə mətnindən təkrar istifadə edir.",
|
||||
"Decorated Pots": "Bəzəkli qablar",
|
||||
"Reuses still pots; break wobble and sherd changes redraw.": "Qazan qabları təkrar istifadə edir; yırğalanmaq və parçalanma dəyişiklikləri yenidən çəkmək.",
|
||||
"Bells": "Zənglər",
|
||||
"Reuses still bells; ringing stays animated.": "Hərəkətsiz zəngləri təkrar istifadə edir; Zəng animasiyalı qalır.",
|
||||
"Chests": "Sinələr",
|
||||
"Reuses closed chests; moving lids stay animated.": "Qapalı sandıqları təkrar istifadə edir; hərəkət edən qapaqlar canlı qalır.",
|
||||
"Banners": "Bannerlər",
|
||||
"Reuses poles; flags and pattern layers still update.": "Dirəkləri təkrar istifadə edir; bayraqlar və naxış qatları hələ də yenilənir.",
|
||||
"Copper Golem Statues": "Mis Qolem heykəlləri",
|
||||
"Reuses statue geometry until its block state changes.": "Blok vəziyyəti dəyişənə qədər heykəlin həndəsəsindən təkrar istifadə edir.",
|
||||
"Leaf Culling": "Yarpaqların kəsilməsi",
|
||||
"Every leaf face. Vanilla's fancy leaves.": "Hər yarpaq üzü. Vanilin gözəl yarpaqları.",
|
||||
"Distant Plant Dither": "Uzaq Bitki Dither",
|
||||
"Keeps fine plants in high-res packs from fading far away.": "Yüksək dəqiqlikli paketlərdəki incə bitkilərin uzaqdan solmasını qarşısını alır.",
|
||||
"Screenshot Quality": "Ekran Şotunun Keyfiyyəti",
|
||||
"F2 screenshots at this many times the game's resolution. Higher takes longer.": "F2 ekran görüntüləri bu dəfələrlə oyunun həlli. Yüksək daha uzun çəkir.",
|
||||
"Frame Generation": "Çərçivə Yaradılması",
|
||||
"Shows a made-up frame between each two real ones: smoother, a little more lag.": "Hər iki real arasında düzəldilmiş çərçivəni göstərir: daha hamar, bir az daha gecikmə.",
|
||||
"Shadow Cache": "Kölgə önbelleği",
|
||||
"Reuses the pack shadow map when sun, view and world match. Off by default.": "Günəş, görünüş və dünya uyğunlaşdıqda paket kölgə xəritəsindən təkrar istifadə edir. Defolt olaraq söndürülür.",
|
||||
"Find BlueMap": "BlueMap tapın",
|
||||
"On servers, finds their BlueMap web map for far terrain. Next join.": "Serverlərdə uzaq ərazilər üçün BlueMap veb xəritəsini tapır. Növbəti qoşulun.",
|
||||
"How far around you BlueMap tiles are downloaded. Next join.": "Ətrafınızda BlueMap plitələri nə qədər yüklənir. Növbəti qoşulun.",
|
||||
"Synchronous": "Sinxron",
|
||||
"Asynchronous": "Asinxron",
|
||||
"Solid": "Möhkəm",
|
||||
"Solid Aggressive": "Möhkəm Aqressiv",
|
||||
"Hollow": "Boş",
|
||||
"Leaves fully inside a canopy draw solid: fewer see-through layers.": "Tam örtünün içindəki yarpaqlar möhkəm çəkilir: daha az keçirici təbəqə.",
|
||||
"Leaves with one open side draw solid too: faster, chunkier edges.": "Bir tərəfi açıq olan yarpaqlar da bərk çəkir: daha sürətli, daha sıx kənarlar.",
|
||||
"Drops faces between leaves: faster, but gaps look through.": "Yarpaqlar arasında üzləri düşür: daha sürətli, lakin boşluqlar içəri baxır.",
|
||||
"Hotbar: Previous Slot": "İsti panel: Əvvəlki yuva",
|
||||
"Hotbar: Next Slot": "İsti panel: Növbəti Slot",
|
||||
"horizon.agent.connected.one": "Qoşuldu: 1 agent bağlantısı",
|
||||
"horizon.agent.connected.many": "Qoşuldu: %s agent əlaqələri",
|
||||
"horizon.agent.connected.one_ago": "Qoşuldu: 1 agent bağlantısı, son əmr %s s əvvəl",
|
||||
"horizon.agent.connected.many_ago": "Qoşuldu: %s agent əlaqələri, son əmr %s s əvvəl",
|
||||
"horizon.agent.waiting": "Agent gözləyir.",
|
||||
"horizon.agent.off": "Off: agentlər bu oyuna daxil ola bilməz.",
|
||||
"horizon.agent.session_opened": "Oyuna başlayan proqram tərəfindən bu sessiya üçün açıldı.",
|
||||
"horizon.agent.socket": "Soket: %s (tam yolu üçün təfərrüatları kopyalayın)",
|
||||
"horizon.agent.local_only": "Yalnız yerli: bu kompüterdəki agentlər, heç vaxt şəbəkə.",
|
||||
"Auto (%s nits)": "Avtomatik (%s nits)",
|
||||
"Hides models behind opaque blocks. Entities update. Off with custom packs.": "Modelləri qeyri-şəffaf blokların arxasında gizlədir. Müəssisələrin yenilənməsi. Fərdi paketlərlə endirim.",
|
||||
"horizon.extras.repro_keys": "Qısayolların qeyd edilməsi",
|
||||
"horizon.extras.repro_keys.tooltip": "F3+R repro qeydini başlayır və ya dayandırır və F3+E öz paketini yazır. Defolt olaraq söndürülür: yazı dünyanı kopyalayır.",
|
||||
"horizon.agent.record_session": "Səs yazmağa başlayın",
|
||||
"horizon.agent.record_stop": "Səs yazmağı dayandırın",
|
||||
"horizon.agent.export_repro": "Repro paketini ixrac edin",
|
||||
"horizon.repro.started": "Qeydiyyat başladı; F3+R onu dayandırır və paketi yazır.",
|
||||
"horizon.repro.stopped": "Qeydiyyat dayandırıldı: %s",
|
||||
"horizon.repro.bundle": "Repro paketi: %s",
|
||||
"horizon.repro.error": "Reproduksiya: %s",
|
||||
"horizon.repro.no_recording": "İxrac etmək üçün hələ heç bir qeyd yoxdur.",
|
||||
"horizon.repro.replay_started": "Təkrar başladı: %s",
|
||||
"horizon.pack.addInfo": "Modrinth-dən resurs paketi əlavə edin",
|
||||
"horizon.pack.addWorking": "Modrinthdən soruşur...",
|
||||
"horizon.pack.addNone": "Heç bir resurs paketi tapılmadı",
|
||||
"horizon.pack.addTitle": "Resurs Paketi əlavə edin",
|
||||
"horizon.pack.install": "Quraşdırın",
|
||||
"horizon.pack.installing": "Quraşdırılır",
|
||||
"horizon.pack.installed": "Quraşdırılıb",
|
||||
"horizon.pack.search": "Axtar",
|
||||
"horizon.pack.searchHint": "Modrinth axtar...",
|
||||
"horizon.pack.filters": "Filtrlər",
|
||||
"horizon.pack.filter.realistic": "Realist",
|
||||
"horizon.pack.filter.simplistic": "Sadə",
|
||||
"horizon.pack.filter.vanillaLike": "Vanil kimi",
|
||||
"horizon.pack.addFailed": "Paketi əlavə etmək mümkün olmadı: %s",
|
||||
"horizon.extras.header.cosmetics": "Kosmetika",
|
||||
"horizon.extras.cosmetics_mine": "Kosmetikam",
|
||||
"horizon.extras.cosmetics_mine.tooltip": "Gizli: hər Horizon oyunçu sizi kosmetikanız olmadan görür. Başlatma şkafı ilə eyni açar.",
|
||||
"horizon.extras.cosmetics_others": "Digər oyunçuların kosmetikası",
|
||||
"horizon.extras.cosmetics_others.tooltip": "Digər Horizon oyunçular nə geyinirlər: hər şey, yalnız ad etiketi üslubları və ya heç nə. Gizli, oyun heç vaxt nə geyindiklərini soruşmur.",
|
||||
"horizon.extras.cosmetics_auras": "Başqalarının auraları və izləri",
|
||||
"horizon.extras.cosmetics_auras.tooltip": "Digər oyunçuların geydiyi auralar və izlər. Defolt olaraq söndürülür.",
|
||||
"horizon.extras.cosmetics.shown": "Göstərildi",
|
||||
"horizon.extras.cosmetics.hidden": "Gizli",
|
||||
"horizon.extras.cosmetics.name_tags": "Yalnız ad etiketləri"
|
||||
}
|
||||
@@ -0,0 +1,496 @@
|
||||
{
|
||||
"horizon.options.controller": "Контролер",
|
||||
"horizon.options.three_d_skin_layers": "3D скин ҡатламдары",
|
||||
"horizon.options.vibration": "Вибрация",
|
||||
"horizon.options.adaptive_triggers": "Адаптив триггерҙар",
|
||||
"horizon.options.lightbar": "Лайтбар",
|
||||
"horizon.options.look_sensitivity": "Ҡарау һиҙгерлеге",
|
||||
"horizon.options.invert_x": "Ҡараш инверсияһы X",
|
||||
"horizon.options.invert_y": "Ҡараш инверсияһы Y",
|
||||
"horizon.options.sneak_button": "Боҫоу төймәһе",
|
||||
"horizon.options.move_deadzone": "Хәрәкәт үле зонаһы",
|
||||
"horizon.options.look_deadzone": "Ҡараш үле зонаһы",
|
||||
"horizon.options.button_glyphs": "Төймә глифтары",
|
||||
"horizon.options.on_screen_keyboard": "Экрандағы клавиатура",
|
||||
"horizon.options.chat_delay": "Чат тотҡарланыуы",
|
||||
"horizon.options.lightbar.health": "Һаулыҡ",
|
||||
"horizon.options.lightbar.dimension": "Үлсәм",
|
||||
"horizon.options.glyphs.auto": "Авто",
|
||||
"horizon.options.keyboard.auto": "Авто",
|
||||
"horizon.options.unavailable": "Был функция Horizon-ла әлегә юҡ.",
|
||||
"horizon.options.search": "Эҙләү параметрҙары...",
|
||||
"horizon.pages.mods": "Модтар",
|
||||
"horizon.pages.shader_packs": "Шейдер пакеттары",
|
||||
"horizon.pages.shader_options": "Шейдер параметрҙары",
|
||||
"horizon.pages.controller": "Контроллер параметрҙары",
|
||||
"horizon.pages.controller_binds": "Контроллер бәйләй",
|
||||
"horizon.pages.extras": "Horizon Өҫтәмә",
|
||||
"horizon.pages.settings": "Horizon Көйләүҙәр",
|
||||
"horizon.pages.agent": "ЯИ агенты",
|
||||
"horizon.split.leave": "Ҡалдырырға",
|
||||
"horizon.pages.split_settings": "Сплит-экран параметрҙары",
|
||||
"horizon.pages.split_profiles": "Кем уйнай?",
|
||||
"horizon.pages.split_setup": "Сплит-экранды ҡуйыу",
|
||||
"horizon.pages.music": "Музыка",
|
||||
"horizon.pages.music.menu": "Меню",
|
||||
"horizon.pages.music.overworld": "Өҫтөн донъя",
|
||||
"horizon.pages.music.creative": "Ижади .",
|
||||
"horizon.pages.music.underwater": "Һыу аҫтында .",
|
||||
"horizon.pages.music.end": "Аҙағы",
|
||||
"horizon.pages.music.boss": "Етәксе",
|
||||
"horizon.pages.music.credits": "Кредиттар",
|
||||
"horizon.pages.music.overworld_biomes": "Донъя өҫтөндәге биомдар",
|
||||
"horizon.pages.music.nether_biomes": "Недер биомдары",
|
||||
"horizon.pages.music.end_biomes": "Аҙаҡҡы биомдар",
|
||||
"horizon.pages.music.other": "Башҡа музыка .",
|
||||
"horizon.pages.music.empty": "Музыка тректары юҡ: уйындың тауыштары тейәлмәгән.",
|
||||
"horizon.pages.music.tooltip": "Встроенный тректар, хәл буйынса: хәҙер бер уйнай, йәки теләһә ниндәй һүндерергә, шулай итеп, уйын уны йыйыу туҡтата.",
|
||||
"horizon.pages.settings.tooltip": "Horizon үҙ параметрҙары: графика, контроллерҙар, өҫтәмәләр һәм модтар.",
|
||||
"horizon.pages.graphics.tooltip": "Графика, ябай: һәр параметр нимәгә төшкәнен әйтә.",
|
||||
"horizon.pages.graphics_advanced.tooltip": "Һәр график параметр, Horizon’s инә, һәр береһе нимә менән.",
|
||||
"horizon.pages.controller.tooltip": "Контроллерҙар: уларҙың төймәләре, таяҡсалар, вибрация һәм меню навигацияһы.",
|
||||
"horizon.pages.extras.tooltip": "Факультатив өҫтәүҙәр, бөтәһе лә өҫтөндә ғәҙәттәгесә: уйын ваниль ҡала, тик һеҙ бер өҫтөндә.",
|
||||
"horizon.pages.agent.tooltip": "Һеҙҙең үҙ AI агент уйнай: horizon-ctl һәм MCP клиенттар был компьютерҙа.",
|
||||
"horizon.pages.split_profiles.tooltip": "Кем уйнай: был уйын папкаһында һаҡланған профиль.",
|
||||
"horizon.pages.split_setup.tooltip": "Тәҙрәләр һәм мониторҙар, ә кем ҡайҙа уйнай.",
|
||||
"horizon.pages.shader_packs.tooltip": "Шейдер пакеттары шейдерпакеттар папкаһынан: Horizon үҙ һәм шейдерҙар/ форматындағылар. Берәм-берәм йүгерә.",
|
||||
"horizon.pages.mods.tooltip": "Horizon өсөн эшләнгән модтар, горизонт-модтар папкаһынан. Һәр береһе ҡом йәшниктә йүгерә һәм һеҙ уны тоҡандырғансы һүндерелә.",
|
||||
"horizon.pages.open.graphics": "Графика...",
|
||||
"horizon.pages.open.graphics_advanced": "Алдынғы графика...",
|
||||
"horizon.pages.open.shader_packs": "Шейдер пакеттары...",
|
||||
"horizon.pages.open.controller": "Контроллер параметрҙары...",
|
||||
"horizon.pages.open.split_setup": "Бүленгән экран...",
|
||||
"horizon.pages.open.extras": "Өҫтәмәләр...",
|
||||
"horizon.pages.open.mods": "Модтар...",
|
||||
"horizon.pages.open.agent": "ЯИ агенты...",
|
||||
"horizon.pages.open.horizon_graphics": "Horizon Графика...",
|
||||
"horizon.pages.open.controller_binds": "Контроллер бәйләй...",
|
||||
"horizon.pages.open.horizon_settings": "Horizon Көйләүҙәр...",
|
||||
"horizon.pages.open.music": "Музыка...",
|
||||
"horizon.mods.empty": "Модтар юҡ: .hmod файлдарын горизонт-модтар папкаһына ҡуйығыҙ",
|
||||
"horizon.mods.stopped": " (Туҡтатылған)",
|
||||
"horizon.mods.not_built": " (Төҙөлмәгән)",
|
||||
"horizon.mods.dev": " (Дев)",
|
||||
"horizon.mods.settings": "Көйләүҙәр",
|
||||
"horizon.mods.in_world": " (донъяны үҙгәртергә ҡалдырырға)",
|
||||
"horizon.mods.open_folder": "Мод папкаһын асыу",
|
||||
"horizon.shader_packs.empty": "Шейдер пакеттары юҡ: уларҙы шейдерпакеттар папкаһына һалығыҙ",
|
||||
"horizon.shader_options.open": "Шейдер варианттары...",
|
||||
"horizon.shader_options.profile": "Профиль",
|
||||
"horizon.shader_options.loading": "Шейдер пакетының варианттарын уҡыу...",
|
||||
"horizon.agent.copy_details": "Тоташыу тураһында мәғлүмәтте күсерергә",
|
||||
"horizon.multiplayer.join": "Ҡушылыу",
|
||||
"horizon.multiplayer.cancel_reconnecting": "Яңынан тоташтырыуҙы юҡҡа сығарыу",
|
||||
"horizon.multiplayer.join_friend": "Дуҫҡа ҡушыл",
|
||||
"horizon.multiplayer.invite_code": "Саҡырыу коды",
|
||||
"horizon.multiplayer.relay": "Реле (теләк буйынса)",
|
||||
"Preset": "Алдан ҡуйылған",
|
||||
"LOD Distance": "LOD арауығы",
|
||||
"Far Detail": "Алыҫ деталь",
|
||||
"Cave Culling": "Мәмерйә ҡырҡыу",
|
||||
"Entity Culling": "Субъектты ҡырҡыу",
|
||||
"Chunk Updates": "Яңыртыу өлөштәре",
|
||||
"Upload Budget": "Бюджет тейәү",
|
||||
"Sky": "Күк",
|
||||
"Fog": "Томан",
|
||||
"Weather": "Һауа торошо",
|
||||
"Animated Textures": "Йәнле текстуралар",
|
||||
"Present Mode": "Хәҙерге режим",
|
||||
"Frame Pacing": "Кадр темпы",
|
||||
"Worker Threads": "Эшсе ептәр",
|
||||
"Resolution Scale": "Асыҡлыҡ шкалаһы",
|
||||
"Anti-aliasing": "Анти-псевдоним",
|
||||
"Upscaling": "Масштаблаштырыу",
|
||||
"Paper White": "Аҡ ҡағыҙ",
|
||||
"Peak Brightness": "Иң юғары яҡтылыҡ",
|
||||
"Black Level": "Ҡара кимәл",
|
||||
"UI Brightness": "Яҡтылыҡ",
|
||||
"Battery Mode": "Аккумулятор режимы",
|
||||
"Graphics API": "Графика API",
|
||||
"Translucent Batching": "Ярым үтә күренмәле партиялау",
|
||||
"Performance Overlay": "Һөҙөмтәлелек өҫтөнлөктәре",
|
||||
"Full Detail Distance": "Тулы ентекле арауыҡ",
|
||||
"On": "Өҫтөндә",
|
||||
"Off": "Һүндерелгән",
|
||||
"Unlimited": "Сикләнмәгән",
|
||||
"Auto": "Авто",
|
||||
"Custom": "Ҡулланыусы",
|
||||
"Performance": "Башҡарыу",
|
||||
"Balanced": "Баланслы",
|
||||
"Quality": "Сифат",
|
||||
"Ultra": "Ультра",
|
||||
"Ultra Performance": "Ультра етештереүсәнлеге",
|
||||
"Native": "Натив",
|
||||
"Full": "Тулы",
|
||||
"Reduced": "Кәметелгән",
|
||||
"Efficient": "Һөҙөмтәле",
|
||||
"Precise": "Теүәл",
|
||||
"Auto (VSync)": "Авто (ВСинхронизация)",
|
||||
"FIFO": "ФИФО",
|
||||
"Mailbox": "Почта йәшниге",
|
||||
"Immediate": "Шунда уҡ",
|
||||
"FPS and Graph": "FPS һәм график",
|
||||
"TAA": "ТАА",
|
||||
"FXAA": "ФХАА",
|
||||
"No cost": "Хаҡы юҡ",
|
||||
"Low cost": "Түбән хаҡ",
|
||||
"Medium cost": "Уртаса хаҡ",
|
||||
"High cost": "Юғары хаҡ",
|
||||
"Saves time": "Ваҡытты экономиялай",
|
||||
"Graphics": "Графика",
|
||||
"Done": "Бөттө",
|
||||
"This feature is not yet available in Horizon.": "Был функция Horizon-ла әлегә юҡ.",
|
||||
"Your display or system doesn't offer HDR output.": "Һеҙҙең дисплей йәки система тәҡдим итмәй HDR сығыш.",
|
||||
"Turn HDR on to use it.": "Уны ҡулланыу өсөн HDR ҡабыҙығыҙ.",
|
||||
"Your GPU or graphics API doesn't support it.": "Һеҙҙең GPU йәки график API уны ҡабул итмәй.",
|
||||
"%s chunks": "%s өлөштәр",
|
||||
"%s per frame": "%s бер кадрға",
|
||||
"%s MiB/frame": "%s МиБ/кадр",
|
||||
"%s KiB/frame": "%s КиБ/кадр",
|
||||
"Auto (%s)": "Авто (%s)",
|
||||
"Full-detail terrain range. LOD Distance can extend local worlds farther.": "Тулы деталь ер диапазоны. LOD Дистанция урындағы донъяларҙы алыҫҡараҡ һуҙырға мөмкин.",
|
||||
"Coarse distant terrain in local worlds. Integrated GPUs stop at 128 chunks.": "Урындағы донъяларҙа ҡырыҫ алыҫ ерҙәр. Интеграцияланған график процессорҙар 128 өлөштә туҡтай.",
|
||||
"Reduced draws far terrain coarser: faster on this integrated GPU.": "Ҡыҫҡартылған тарта алыҫ ер ҡырыҫ: тиҙерәк был интеграцияланған GPU.",
|
||||
"Reduced draws far terrain coarser, for GPUs it slows down.": "Кәметелгән тарта алыҫ ер ҡырыҫыраҡ, GPUs өсөн ул яйлатып.",
|
||||
"Field of view. Wider shows more terrain at once.": "Күренеш өлкәһе. Киңерәк бер юлы күберәк ерҙе күрһәтә.",
|
||||
"Caps frames per second; a cap saves power and heat.": "Ҡапҡастар кадрҙар секундына; ҡапҡас энергияны һәм йылылыҡты һаҡлай.",
|
||||
"Waits for the display's refresh: no tearing, a little latency.": "Дисплейҙы яңыртыуҙы көтә: йыртыу юҡ, бер аҙ тотҡарлыҡ.",
|
||||
"Size of menus and the HUD.": "Размер меню һәм HUD.",
|
||||
"Sets the options below together. Changing one makes it Custom.": "Түбәндәге варианттарҙы бергә ҡуя. Бер үҙгәртеү уны Ҡулланыусы итә.",
|
||||
"Lava, fire and sunlight shine brighter than white. Needs an HDR display.": "Лава, ут һәм ҡояш нурҙары аҡтан да сағыуыраҡ балҡый. HDR дисплей кәрәк.",
|
||||
"Your display's darkest black. 0 for OLED; LCDs glow a little.": "Һеҙҙең дисплей’ы иң ҡара ҡара. 0 өсөн OLED; ЖК-дисплейҙар бер аҙ балҡый.",
|
||||
"How bright highlights get. Auto: the peak your system reports.": "Нисек сағыу өҫтөнлөктәр ала. Авто: пик һеҙҙең система отчеттар.",
|
||||
"How bright white paper and menus look. Auto: your desktop's white.": "Нисек сағыу аҡ ҡағыҙ, менюлар күренә. Авто: һеҙҙең өҫтәл’ы аҡ.",
|
||||
"How bright the HUD and menus are, against paper white.": "Нисек сағыу HUD һәм менюлар, ҡағыҙ аҡ ҡаршы.",
|
||||
"How far mobs, crops and machines keep working. CPU time.": "Күпме алыҫҡа мобтар, культуралар һәм машиналар эшләп тора. Процессор ваҡыты.",
|
||||
"How far away mobs and items are drawn, as a share of normal.": "Нисек алыҫҡа мобтар һәм әйберҙәр тартыла, өлөшө булараҡ нормаль.",
|
||||
"Skips terrain hidden behind closed sections. Off costs a lot.": "Ябыҡ участкалар артында йәшеренгән ерҙәрҙе һикерә. Офф күп сығымдар талап итә.",
|
||||
"Hides entities behind opaque blocks.": "Һүҙ асыҡ булмаған блоктар артында субъекттарҙы йәшерә.",
|
||||
"No entity occlusion culling.": "Юҡ субъект окклюзия ҡырҡыу.",
|
||||
"CPU occlusion test runs this frame.": "Процессор окклюзия һынау был кадрҙа эшләй.",
|
||||
"Occlusion checks run on a worker thread.": "Окклюзия тикшерелеүҙәре эшсе ептә эшләй.",
|
||||
"Meshed sections uploaded per frame. Lower is smoother while loading.": "Бер кадрға тейәлгән селтәрле бүлектәр. Түбәнге тейәгәндә шымараҡ.",
|
||||
"Soft shadows in corners. Costs chunk building time only.": "Мөйөштәрҙә йомшаҡ күләгәләр. Сығымдар өлөшө төҙөү ваҡыты ғына.",
|
||||
"Smaller copies of block textures for distant terrain: less shimmer.": "Алыҫ ерҙәр өсөн блок текстураларының бәләкәйерәк күсермәләре: ялтырап тороу аҙыраҡ.",
|
||||
"Blends grass and water colours across biomes when building chunks.": "Үлән һәм һыу төҫтәрен биомдар буйынса ҡатнаштырып, өлөштәр төҙөгәндә.",
|
||||
"Cloud layer: off, flat (fast) or 3D (fancy).": "Болот ҡатламы: өҙөлгән, яҫы (тиҙ) йәки 3D (фантазия).",
|
||||
"How far clouds reach, in chunks.": "Болоттар ни тиклем алыҫҡа етә, өлөшләп.",
|
||||
"Draws the sky, sun, moon and stars.": "Күкте, ҡояшты, айҙы, йондоҙҙарҙы һүрәтләй.",
|
||||
"Distance fog. Off shows the edge of the loaded world.": "Дистанция томан. Off йөкләнгән донъяның ситен күрһәтә.",
|
||||
"Draws rain and snow.": "Ямғыр һәм ҡар тарта.",
|
||||
"How far rain and snow fall around you.": "Тирә-яғыңда ни тиклем алыҫҡа ямғыр, ҡар яуа.",
|
||||
"How many particles effects spawn.": "Күпме киҫәксә эффекттары үрсетә.",
|
||||
"Round shadows under mobs and items.": "Мобтар һәм әйберҙәр аҫтында түңәрәк күләгәләр.",
|
||||
"Leaves with see-through gaps. Off draws them solid.": "Япраҡтары үтә күренмәле тишектәр менән. Офф уларҙы ныҡлы тарта.",
|
||||
"Sorts water and glass more exactly behind each other.": "Һыу менән быяланы бер-береһе артында анығыраҡ сорттарға айыра.",
|
||||
"Which chunk rebuilds wait for the frame: none, nearby or yours.": "Ниндәй өлөшө яңынан төҙөй көтә рамка: бер ниндәй ҙә, яҡында йәки һеҙҙең.",
|
||||
"Animates water, lava, fire and other moving textures.": "Һыу, лава, ут һәм башҡа хәрәкәт итеүсе текстураларҙы йәнләндерә.",
|
||||
"World pixels per screen pixel. Below 100% is faster on the GPU.": "Донъя пикселдәре экран пикселе. 100% түбән тиҙерәк GPU.",
|
||||
"Smooths jagged edges. FXAA: softer. TAA: smoothest, moving things may trail.": "Тешле ситтәрен тигеҙләй. ФХАА: йомшағыраҡ. ТАА: иң шыма, хәрәкәт итеүсе әйберҙәр эҙҙәре булыуы мөмкин.",
|
||||
"Renders the world smaller and rebuilds it with TAA. Faster, softer.": "Донъяны бәләкәйерәк итә һәм уны ТАА менән яңынан төҙөй. Тиҙерәк, йомшағыраҡ.",
|
||||
"HDR output on an HDR display: lava, fire and sunlight shine brighter.": "HDR дисплейында HDR сығышы: лава, ут һәм ҡояш нурҙары сағыуыраҡ балҡый.",
|
||||
"How frames reach the screen while VSync is off.": "Нисек кадрҙар экранға етә, ә VSync өҙөлгән.",
|
||||
"Efficient sleeps until the next frame; Precise spins, like vanilla.": "Һөҙөмтәле йоҡлай сираттағы кадрға тиклем; Теүәл әйләнештәр, ваниль кеүек.",
|
||||
"Fills the screen (borderless).": "Экранды тултыра (сикһеҙ).",
|
||||
"Brightens dark places.": "Ҡараңғы урындарҙы яҡтырта.",
|
||||
"Lowers the frame rate when minimised, or idle too.": "Кадрҙар йышлығын түбәнәйтә, ҡасан минималь, йәки буш ла.",
|
||||
"Sways the view while walking.": "Йөрөгәндә ҡарашты һелкетә.",
|
||||
"Fades newly loaded chunks in.": "Яңы тейәлгән өлөштәрҙе һүнә.",
|
||||
"Darkens the screen's edges.": "Экрандың ситтәрен ҡарайта.",
|
||||
"Shows when the world saves.": "Донъя ҡотҡарғанда күрһәтә.",
|
||||
"Shows attack cooldown.": "Һөжүм итеү ваҡытын күрһәтә.",
|
||||
"60 FPS cap (30 in menus or unfocused), half the workers: less power.": "60 FPS ҡапҡас (30 менюларҙа йәки нефокусированный), яртыһы эшселәр: ҡөҙрәте аҙыраҡ.",
|
||||
"Threads that generate, light and mesh chunks. Next start.": "Ептәр, генерациялау, яҡтылыҡ һәм селтәр өлөштәре. Киләһе старт.",
|
||||
"Vulkan, then DirectX 12 (Windows) or OpenGL (Linux) where it fails. Next start.": "Vulkan, унан һуң DirectX 12 (Windows) йәки OpenGL (Linux) ҡайҙа уңышһыҙлыҡҡа осрай. Киләһе старт.",
|
||||
"Water and glass in one buffer: fewer draw calls, a bit more VRAM. Next start.": "Һыу һәм быяла бер буферҙа: низағ шылтыратыуҙар аҙыраҡ, бер аҙ күберәк VRAM. Киләһе старт.",
|
||||
"Mesh data sent to the GPU per frame. Lower is smoother while loading.": "Селтәр мәғлүмәттәре ебәрелгән GPU бер кадр. Түбәнге тейәгәндә шымараҡ.",
|
||||
"Frame rate and frame times over the game, with a graph.": "Кадрҙар тиҙлеге һәм кадрҙар ваҡыты өҫтөндә уйын, график менән.",
|
||||
"horizon.multiplayer.finding_friend": "Дуҫыңдың донъяһын табыу...",
|
||||
"horizon.multiplayer.not_signed_in": "Был сервер онлайн режимда. Уға ҡушылыу өсөн Microsoft иҫәп яҙмағыҙ менән Horizon стартерында инегеҙ.",
|
||||
"horizon.multiplayer.invalid_address": "Дөрөҫ булмаған сервер адресы: %s",
|
||||
"horizon.multiplayer.connected_friend_direct": "Һеҙҙең дуҫығыҙға туранан-тура тоташтырылған...",
|
||||
"horizon.multiplayer.connected_friend_relay": "Һеҙҙең дуҫығыҙға реле аша тоташтырылған...",
|
||||
"General": "Дөйөм",
|
||||
"Advanced": "Алдынғы",
|
||||
"Undo": "Кире ҡайтарыу",
|
||||
"Search options": "Эҙләү варианттары",
|
||||
"Shortcut": "Ярлыҡ",
|
||||
"Distance": "Арауыҡ",
|
||||
"Display": "Дисплей",
|
||||
"Interface": "Интерфейс",
|
||||
"Sky and weather": "Күк йөҙө һәм һауа торошо",
|
||||
"Lighting and entities": "Яҡтыртыу һәм субъекттар",
|
||||
"Textures": "Текстуралар",
|
||||
"Image": "Һүрәт",
|
||||
"Chunk loading": "Ҡыҫҡа тейәү",
|
||||
"Culling": "Куллинг",
|
||||
"Power": "Власть",
|
||||
"Frames": "Рамкалар",
|
||||
"Overlay": "Ҡаплау",
|
||||
"Output": "Сығыш",
|
||||
"Brightness": "Яҡтылыҡ",
|
||||
"How far you see, the window and the HUD.": "Күпме алыҫ күрәһең, тәҙрә һәм HUD.",
|
||||
"The sky and weather, lighting, textures and the image.": "Күк һәм һауа торошо, яҡтыртыу, текстуралар һәм образ.",
|
||||
"Chunk loading, culling and power use.": "Ҡырҡылған тейәү, ҡырҡыу һәм ҡөҙрәт ҡулланыу.",
|
||||
"How frames reach the screen, and the performance overlay.": "Нисек кадрҙар экранға етә, һәм башҡарыу өҫтәү.",
|
||||
"Brighter-than-white output on an HDR display.": "HDR дисплейында аҡтан сағыуыраҡ сығыш.",
|
||||
"Results for \"%s\"": "\"%s\" өсөн һөҙөмтәләр.",
|
||||
"No settings match.": "Бер ниндәй ҙә параметрҙар тап килмәй.",
|
||||
"horizon.title.not_affiliated": "Mojang йәки Microsoft менән бәйле түгел",
|
||||
"horizon.extras.header.lighting": "Яҡтыртыу",
|
||||
"horizon.extras.header.third_person": "Өсөнсө зат .",
|
||||
"horizon.extras.header.particles": "Киҫәксәләр",
|
||||
"horizon.extras.header.inventory": "Инвентаризация",
|
||||
"horizon.extras.header.chat": "Чат",
|
||||
"horizon.extras.header.multiplayer": "Күп уйынсылар",
|
||||
"horizon.extras.header.sound": "Тауыш .",
|
||||
"horizon.extras.header.menus": "Менюлар",
|
||||
"horizon.extras.fullbright": "Фуллбрайт",
|
||||
"horizon.extras.dynamic_lights": "Динамик яҡтылыҡ",
|
||||
"horizon.extras.own_name_tag": "Үҙ исем билдәһе",
|
||||
"horizon.extras.hide_block_particles": "Блок-өҙөү киҫәксәләрен йәшерергә",
|
||||
"horizon.extras.auto_reconnect": "Авто-яңынан тоташтырыу",
|
||||
"horizon.extras.ui_sound_reserve": "Ҡулланыусылар интерфейсы тауыштары өсөн каналдар һаҡлау",
|
||||
"horizon.extras.music_page": "Музыка бите .",
|
||||
"horizon.extras.mouse_tweaks": "Сысҡандың идара итеү элементтарын үҙгәртә",
|
||||
"horizon.extras.mouse_tweaks_wheel": "Прокрутка тәгәрмәсе әйберҙәрҙе күсерә",
|
||||
"horizon.extras.sort": "Сортлау төймәләре",
|
||||
"horizon.extras.sort_key": "Сортлау асҡысы",
|
||||
"horizon.extras.no_ai": "ЯИ юҡ",
|
||||
"horizon.extras.agent_control": "Агент контроле",
|
||||
"horizon.extras.discord_presence": "Discord Бай булыу",
|
||||
"horizon.extras.splitscreen": "Бүлгән экран",
|
||||
"horizon.extras.chat_animation": "Тигеҙ һөйләшеү",
|
||||
"horizon.extras.chat_indicator": "Хәбәр күрһәткесе",
|
||||
"horizon.extras.wheel_cycles_settings": "Прокрутка тәгәрмәсе параметрҙарҙы үҙгәртә",
|
||||
"horizon.extras.pack_browser": "Ресурс пакеты браузеры",
|
||||
"horizon.extras.fullbright.tooltip": "Блоктарҙы һәм субъекттарҙы тулы яҡтылыҡта, хатта ҡараңғы урындарҙа ла күрһәтегеҙ.",
|
||||
"horizon.extras.dynamic_lights.tooltip": "Факелдар һәм башҡа яҡтылыҡ сығанаҡтары тотолған, төшөрөлгән йәки ут өҫтөндә улар тирәһендәге блоктарҙы яҡтырта.",
|
||||
"horizon.extras.own_name_tag.tooltip": "Һеҙҙең исемде баш өҫтөндә өсөнсө заттан күрһәтә, башҡа уйынсылар күргәнсә. Йәшерен ҡасан сервер һеҙҙең команданың исемдәрен йәшерә йәки һеҙ’күренмәй.",
|
||||
"horizon.extras.hide_block_particles.tooltip": "Йәшерә сүп-сар киҫәксәләре, улар өҙөлгән блоктан ярыла һәм һеҙ шахта өҫтөндә емерек. Башҡа киҫәксәләр ҡала.",
|
||||
"horizon.extras.auto_reconnect.tooltip": "Серверға тоташыу юғалғандан йәки ҡабаттан башлағандан һуң ҡабаттан ҡушыла, бер ҡасан да тибеүҙән йәки тыйыуҙан һуң.",
|
||||
"horizon.extras.ui_sound_reserve.tooltip": "Донъялағы тауыштар 247 тауыш каналының 16-һын бушлай ҡалдыра, шуға күрә уларҙы ташҡын (ҙур шартлау) меню баҫыуҙарын тындыра алмай.",
|
||||
"horizon.extras.music_page.tooltip": "Музыка & Тауыштар ала Музыка... бит: уйнау теләһә ниндәй встроенный трек хәҙер, йәки бер һүндереү, шулай итеп, уйын уны йыйыу туҡтата. Тректы һүндермәйенсә бер нәмә лә үҙгәрмәй.",
|
||||
"horizon.extras.mouse_tweaks.tooltip": "Уң-һөйрәп урындар бер слот, һул-һөйрәп йыя үткәрелгән әйбер, Shift + һул-һөйрәп һәр слот күсә.",
|
||||
"horizon.extras.mouse_tweaks_wheel.tooltip": "Аҫҡа слоттың бер әйберен икенсе яҡҡа ебәрә, өҫкә бер кире килтерә.",
|
||||
"horizon.extras.sort.tooltip": "Сортировать инвентарь, һандыҡтар, бочкалар, эндер һандыҡтар һәм шулкер йәшниктәр ижади вкладка тәртибендә, стека берләштереү.",
|
||||
"horizon.extras.sort_key.tooltip": "Курсор аҫтындағы өлөштө сорттарға бүлә. Баҫығыҙ, һуңынан бер төймәгә баҫығыҙ; Ҡасыу уны сисеп ебәрә.",
|
||||
"horizon.extras.no_ai.tooltip": "Йәшерә һәм һүндерә һәр AI функцияһы: агент менән идара итеү, горизонт-ctl һәм MCP серверҙары. Пускатель’ы переключатель да.",
|
||||
"horizon.extras.agent_control.tooltip": "Һеҙҙең үҙ AI агент был уйынды уйнай ала аша horizon-ctl йәки MCP клиент, был компьютерҙа ғына.",
|
||||
"horizon.extras.discord_presence.tooltip": "Һеҙҙең Discord профилендә Horizon уйнауҙы күрһәтә, ә Discord йүгерә: менюлар, бер уйынсы йәки күп уйынсы, үлсәм һәм уйнаған ваҡыт. Бер ҡасан да донъяның исеме йәки сервер адресы.",
|
||||
"Calibrate...": "Калибрлау...",
|
||||
"Calibrate Anyway...": "Калибрлау барыбер...",
|
||||
"Use Automatic Setup": "Автоматик ҡуйыуҙы ҡулланыу",
|
||||
"Shortcut: %s": "Ҡыҫҡа юл: %s",
|
||||
"Next": "Артабан",
|
||||
"HDR Calibration %s/%s: %s": "HDR калибровкаһы %s/%s: %s",
|
||||
"Sets the three below full screen, one test picture at a time.": "Өс аҫтында тулы экран ҡуя, бер һынау һүрәте бер юлы.",
|
||||
"A key that opens this screen from the game. Not bound at first.": "Уйындан был экранды асҡан асҡыс. Тәүҙә бәйләнмәгән.",
|
||||
"Your display didn't say how bright it gets: calibrate to set it up.": "Һеҙҙең дисплей нисек яҡты ала, тип әйтмәне: калибровка, уны ҡуйырға.",
|
||||
"Already set up for your display. Only calibrate if HDR looks wrong.": "Һеҙҙең дисплей өсөн инде ҡуйылған. Тик калибровка, әгәр HDR дөрөҫ түгел күренә.",
|
||||
"Puts Peak Brightness and Paper White back to your display's setup.": "Ҡуя Пик Яркость һәм Ҡағыҙ Аҡ кире һеҙҙең дисплей’ы ҡороу.",
|
||||
"Set up for your display. Leave on Auto unless it looks wrong.": "Һеҙҙең дисплей өсөн ҡуйырға. Авто өҫтөндә ҡалдырырға, әгәр ҙә ул дөрөҫ күренмәһә.",
|
||||
"Lower it until the logo just disappears into the black.": "Түбән уны тиклем логотип ҡара ғына юғала.",
|
||||
"Raise it until the logo just disappears into the bright square.": "Логотип яҡты квадратҡа ғына юғалғансы уны күтәрегеҙ.",
|
||||
"Make the card a white that's comfortable to look at for a long time, in the light you play in.": "Картаны аҡ төҫтә эшләгеҙ, оҙаҡ ҡарарға уңайлы, һеҙ уйнаған яҡтылыҡта.",
|
||||
"horizon.splitscreen.profiles.forget": "Онот .",
|
||||
"horizon.splitscreen.profiles.create": "Ижад итеү",
|
||||
"horizon.splitscreen.profiles.you": " - һин",
|
||||
"horizon.splitscreen.profiles.forget_named": "Онот %s .",
|
||||
"horizon.splitscreen.profiles.previous": "Алдағы",
|
||||
"horizon.splitscreen.profiles.next": "Артабан",
|
||||
"horizon.splitscreen.profiles.new_button": "Яңы профиль...",
|
||||
"horizon.splitscreen.profiles.forget_title": "Профильде оноттоғоҙмо?",
|
||||
"horizon.splitscreen.profiles.forget_leaves": "Ул был инстанцияның исемлегенән сыға.",
|
||||
"horizon.splitscreen.profiles.forget_kept": "Донъя прогресс һәм параметрҙар һаҡлана.",
|
||||
"horizon.splitscreen.profiles.new_title": "Яңы профиль",
|
||||
"horizon.splitscreen.profiles.name_hint": "Исем (3-тән 16-ға тиклем хәреф, һан, _)",
|
||||
"horizon.splitscreen.profiles.switch_title": "Профиль алмаштырыу",
|
||||
"horizon.splitscreen.profiles.offline_note": "Офлайн профилдәр был данаға ҡарай",
|
||||
"horizon.splitscreen.profiles.move": "Уйнаған ергә күсерегеҙ .",
|
||||
"horizon.splitscreen.profiles.move_place": "Уйнаған урынға күсегеҙ: %s .",
|
||||
"horizon.friends.title": "Дуҫтар менән уйнау .",
|
||||
"horizon.friends.hint": "Дуҫтар кодты титул экранының «Дуҫтар» төймәһенән һуң, туранан-тура бәйләнештә йәки стартердың «Уйнау» битендә йәбештерә.",
|
||||
"horizon.friends.copied": "Күсерелгән",
|
||||
"horizon.friends.copy_code": "Код күсермәһе",
|
||||
"horizon.friends.stop_sharing": "Бүлешеүҙе туҡтатығыҙ",
|
||||
"horizon.friends.none_yet": "Бында әлегә дуҫтар юҡ.",
|
||||
"horizon.friends.here_now": "Бында хәҙер: %s",
|
||||
"horizon.friends.share_intro": "Был донъя менән бүлешергә артында саҡырыу коды: ул LAN асыла, һәм дуҫтар интернетта код менән ҡушыла. Беҙҙең бер сервер ҙа ҡатнашмай.",
|
||||
"horizon.friends.start_sharing": "Бүлешергә башлағыҙ",
|
||||
"horizon.friends.troubleshooting": "Неисправность...",
|
||||
"horizon.friends.stopped": "Саҡырыу коды менән бүлешеүҙе туҡтатты.",
|
||||
"horizon.friends.short_code_changed": "Кемдер дөрөҫ булмаған ҡыҫҡа кодты һынап ҡараны, шуға күрә ул үҙгәрҙе.",
|
||||
"horizon.friends.wrong_code": "Кемдер дөрөҫ булмаған кодты ҡулланып ҡараған.",
|
||||
"horizon.friends.code_ready": "Һеҙҙең саҡырыу коды әҙер: Уйын Менюһы, Дуҫтар менән уйнау. Күсереп яҙып, дуҫтарығыҙға ебәрегеҙ.",
|
||||
"horizon.friends.share_failed": "Донъяны бүлешә алманым: %s",
|
||||
"horizon.friends.finding_route": "Һеҙгә дуҫтар нисек барып етә алыуын табыу...",
|
||||
"horizon.osk.shift": "Смена",
|
||||
"horizon.osk.space": "Йыһан",
|
||||
"horizon.osk.delete": "Юйырға",
|
||||
"horizon.osk.type": "Тип .",
|
||||
"horizon.osk.symbols": "Символдар",
|
||||
"horizon.osk.close": "Ябыҡ",
|
||||
"horizon.extras.chat_animation.tooltip": "Яңы чат һыҙығы һулдан шыуып инә, ә ул һүнә, урынына бөтөн күренә.",
|
||||
"horizon.extras.chat_indicator.tooltip": "Чат һыҙығының һул яғында төҫлө һыҙыҡ.",
|
||||
"horizon.extras.wheel_cycles_settings.tooltip": "Көйләүҙәрҙәге төймә өҫтөндәге прокрутка тәгәрмәсе үҙенең ҡиммәтен үҙгәртә, ванильдәге кеүек. Һүндерелгән, тәгәрмәс исемлекте генә йөрөтә.",
|
||||
"horizon.extras.pack_browser.tooltip": "Һайлау ресурс пакеттары ала өҫтәү төймәһе, эҙләү Modrinth һәм һеҙҙең пакеттар папкаһына пакет ҡуя. Һүндерелгән, уйын бер ҡасан да бәйләнешкә инә Modrinth.",
|
||||
"horizon.extras.splitscreen.tooltip": "Донъяла, икенсе контроллер яңы уйынсы булараҡ ҡушыла ала: баҫығыҙ А, ҡасан ул һорай, һуңынан профиль һайлап һәм ҡайҙа уйнау.",
|
||||
"horizon.splitscreen.setup.monitor": "Монитор %s",
|
||||
"horizon.splitscreen.setup.monitor_unknown": "монитор",
|
||||
"horizon.splitscreen.setup.window": "Тәҙрә %s",
|
||||
"horizon.splitscreen.setup.new_window": "Яңы тәҙрә",
|
||||
"horizon.splitscreen.setup.fill_monitor": "Тултырырға %s",
|
||||
"horizon.splitscreen.setup.done": "Бөттө",
|
||||
"horizon.splitscreen.setup.on": "Өҫтөндә",
|
||||
"horizon.splitscreen.setup.off": "Һүндерелгән",
|
||||
"horizon.splitscreen.setup.player": "Уйынсы %s",
|
||||
"horizon.splitscreen.setup.revert": "Кире ҡайтарыу",
|
||||
"horizon.splitscreen.setup.apply": "Ҡулланыу",
|
||||
"horizon.splitscreen.setup.warning.empty_main": "1-се тәҙрәлә бер кем дә уйнамай: ул йәшенә",
|
||||
"horizon.splitscreen.setup.warning.empty_close": "Тәҙрәлә бер кем дә уйнамай %s: ул Ҡулланыуҙа ябыла",
|
||||
"horizon.splitscreen.setup.warning.empty_new": "Тәҙрәлә бер кем дә уйнамай %s: ул асылмай",
|
||||
"horizon.splitscreen.setup.warning.on_main": "%s тәҙрә 1-се тәҙрә мониторын тултыра: уның уйынсылары 1-се тәҙрәлә уйнай",
|
||||
"horizon.splitscreen.setup.warning.unplugged": "Тәҙрә %s мониторы тоташтырылмаған: уның уйынсылары 1-се тәҙрәлә уйнай",
|
||||
"horizon.splitscreen.setup.status.off": "Сплитскрин һүндерелгән.",
|
||||
"horizon.splitscreen.setup.status.enable_hint": "Уны тоҡандырып, һуңынан бер донъяла икенсе контроллерҙағы төймәгә баҫығыҙ.",
|
||||
"horizon.splitscreen.setup.status.join_hint": "А баҫып, ҡушылырға һәм профиль һайларға.",
|
||||
"horizon.splitscreen.setup.status.idle": "Сплит-экран буш тора",
|
||||
"horizon.splitscreen.setup.status.alone": "Башҡа урындағы уйынсылар юҡ.",
|
||||
"horizon.splitscreen.setup.status.solo_controls": "Яңғыҙ идара итеү һәм контроллер кире бәйләнеш үҙгәрешһеҙ.",
|
||||
"horizon.splitscreen.setup.window_empty": "Тәҙрә %s: буш",
|
||||
"horizon.splitscreen.setup.note.select": "Плеерға баҫығыҙ, йәки уны тәҙрәгә йәки мониторға һөйрәгеҙ.",
|
||||
"horizon.splitscreen.setup.note.apply": "Ҡулланыу өсөн уйнау өсөн был ысул, Ҡайтарыу өсөн кире ҡайтарыу.",
|
||||
"horizon.splitscreen.setup.note.place": "%s ҡайҙа уйнарға тейеш?",
|
||||
"horizon.splitscreen.setup.this_player": "был уйынсы",
|
||||
"horizon.splitscreen.setup.switch_disabled": "Splitscreen һүнә бер тапҡыр башҡа ҡалдырҙы (уларҙы пауза менюһы).",
|
||||
"horizon.splitscreen.setup.window_place": "Тәҙрә %s (%s %s-нан)",
|
||||
"horizon.splitscreen.setup.names": "Исемдәр .",
|
||||
"horizon.splitscreen.setup.identify": "Билдәләү",
|
||||
"horizon.splitscreen.setup.layout.two": "2 бүлешеү: %s",
|
||||
"horizon.splitscreen.setup.layout.three": "3 бүлешеү: %s",
|
||||
"horizon.splitscreen.setup.layout.two.0": "Авто",
|
||||
"horizon.splitscreen.setup.layout.two.1": "Ян-яҡтан .",
|
||||
"horizon.splitscreen.setup.layout.two.2": "Өҫкө һәм аҫҡы .",
|
||||
"horizon.splitscreen.setup.layout.three.0": "Өҫтөндә бер киң",
|
||||
"horizon.splitscreen.setup.layout.three.1": "Һул яҡта бер бейек",
|
||||
"horizon.splitscreen.setup.layout.three.2": "Ян-яҡтан .",
|
||||
"horizon.splitscreen.setup.help.player": "Уларҙы күсерер өсөн %s баҫығыҙ йәки һөйрәгеҙ.",
|
||||
"horizon.splitscreen.setup.help.layout_auto": "%s (тәҙрә киң булғанда йәнәш). Үҙгәртергә баҫығыҙ.",
|
||||
"horizon.splitscreen.setup.help.layout": "%s. Үҙгәртергә баҫығыҙ.",
|
||||
"horizon.splitscreen.setup.help.switch": "Был компьютер өсөн экран бүленгән, өҫтөндә йәки өҫтөндә.",
|
||||
"horizon.splitscreen.setup.help.identify": "Һәр уйынсының ҡарашы ниндәй тәҙрәлә икәнен күрһәтә.",
|
||||
"horizon.splitscreen.setup.help.names": "Һәр уйынсының исеме мөйөшөндә уларҙы ҡарау.",
|
||||
"horizon.splitscreen.setup.help.revert": "Әле ҡулланылмаған үҙгәрештәрҙе кире ҡайтарығыҙ.",
|
||||
"horizon.splitscreen.setup.help.apply": "Картала күрһәтелгәнсә уйнағыҙ.",
|
||||
"horizon.splitscreen.setup.help.unchanged": "Әлегә бер нәмә лә үҙгәрмәне.",
|
||||
"horizon.splitscreen.setup.give_up_pad": "Падтан баш тартығыҙ",
|
||||
"horizon.splitscreen.prompt.controller_connected": "Контроллер тоташтырылған",
|
||||
"horizon.splitscreen.prompt.controller_disconnected": "Контроллер өҙөлгән",
|
||||
"horizon.splitscreen.prompt.controller_disconnected.hint": "Яңынан уны тоташтырырға, йәки икенсе төймәгә баҫығыҙ",
|
||||
"horizon.splitscreen.prompt.join.one": "%s ҡушылырға теләй",
|
||||
"horizon.splitscreen.prompt.join.many": "%s контроллерҙар ҡушылырға теләй",
|
||||
"horizon.splitscreen.prompt.join.yes": "Ҡушылыу",
|
||||
"horizon.splitscreen.prompt.join.as_p1": "Р1 булып уйнай.",
|
||||
"horizon.splitscreen.prompt.join.no": "Юҡ",
|
||||
"horizon.splitscreen.prompt.lost": "%s: контроллер өҙөлгән",
|
||||
"horizon.splitscreen.prompt.lost.use_another": "Икенсе ҡулланыу .",
|
||||
"horizon.splitscreen.prompt.lost.leave": "Ҡалдырырға",
|
||||
"horizon.splitscreen.setup.help.give_up_pad": "Һеҙҙең контролер һеҙҙе водитель туҡтата һәм ҡушылырға тәҡдим ителә (А).",
|
||||
"horizon.splitscreen.setup.note.held_at": "%s %s тиклем: А уны бында төшөрә, В кире һала.",
|
||||
"horizon.splitscreen.setup.note.held": "%s йыйып алынған: һул/уң ҡайҙа йыйып ала, А төшә, В кире һала.",
|
||||
"horizon.splitscreen.online_only": "Был сервер онлайн режимда: офлайн профилдәр уға ҡушыла алмай, һәр уйынсыға үҙ Minecraft иҫәбе кәрәк.",
|
||||
"horizon.splitscreen.own_account": "Был серверға һәр уйынсының үҙ Minecraft иҫәбе кәрәк",
|
||||
"horizon.splitscreen.local_only": "Башҡа уйынсылар был серверға үҙҙәренең Minecraft иҫәбенә генә ҡушыла ала: офлайн профилдәр һеҙҙең донъяла, LAN йәки һеҙҙең урындағы селтәрҙәге серверҙа уйнай.",
|
||||
"Hides models behind opaque blocks. Async checks off-thread; entities tick.": "Моделдәрҙе асыҡ булмаған блоктар артында йәшерә. Ассинхрон тикшерә тышҡы еп; субъекттар галочкой.",
|
||||
"Block Entities": "Блок субъекттары",
|
||||
"Shulker Boxes": "Шулкер йәшниктәре",
|
||||
"Reuses settled boxes; lid movement stays animated.": "Ҡабаттан ҡуллана урынлаштырылған йәшниктәр; ҡапҡас хәрәкәте йәнле ҡала.",
|
||||
"Signs": "Билдәләре",
|
||||
"Reuses sign text until text, light, or font changes.": "Текст, яҡтылыҡ йәки шрифт үҙгәргәнсе билдә тексын ҡабаттан ҡуллана.",
|
||||
"Decorated Pots": "Биҙәкле һауыттар .",
|
||||
"Reuses still pots; break wobble and sherd changes redraw.": "Һаман да ҡаҙандарҙы ҡабаттан ҡуллана; өҙөү качаться һәм шерд үҙгәрештәр перерисовать.",
|
||||
"Bells": "Ҡыңғырауҙар",
|
||||
"Reuses still bells; ringing stays animated.": "Ҡабаттан ҡуллана әле ҡыңғырауҙар; шылтыратыу йәнле ҡала.",
|
||||
"Chests": "Һандыҡтар",
|
||||
"Reuses closed chests; moving lids stay animated.": "Ябыҡ һандыҡтарҙы ҡабаттан ҡуллана; хәрәкәт итеүсе ҡапҡастар йәнле булып ҡала.",
|
||||
"Banners": "Баннерҙар",
|
||||
"Reuses poles; flags and pattern layers still update.": "Бағаналарҙы ҡабаттан ҡуллана; флагтар һәм өлгө ҡатламдары һаман да яңыртыла.",
|
||||
"Copper Golem Statues": "Баҡыр Голем статуялары",
|
||||
"Reuses statue geometry until its block state changes.": "Блок хәле үҙгәргәнсе статуя геометрияһын ҡабаттан ҡуллана.",
|
||||
"Leaf Culling": "Япраҡ ҡырҡыу",
|
||||
"Every leaf face. Vanilla's fancy leaves.": "Һәр япраҡ йөҙө. Ванильдың фантазия япраҡтары.",
|
||||
"Distant Plant Dither": "Алыҫ үҫемлек ҡалтыраныуы",
|
||||
"Keeps fine plants in high-res packs from fading far away.": "Юғары асыҡлыҡтағы пакеттарҙағы ваҡ үҫемлектәрҙе алыҫҡа һүнеүҙән һаҡлай.",
|
||||
"Screenshot Quality": "Скриншот сифаты",
|
||||
"F2 screenshots at this many times the game's resolution. Higher takes longer.": "F2 скриншоттар был күп тапҡыр уйын’ы ҡарар. Юғары оҙағыраҡ ваҡыт ала.",
|
||||
"Frame Generation": "Кадр быуын",
|
||||
"Shows a made-up frame between each two real ones: smoother, a little more lag.": "Һәр ике ысын араһында ҡоролған кадр күрһәтә: шымараҡ, бер аҙ күберәк лаг.",
|
||||
"Shadow Cache": "Күләгә кэш",
|
||||
"Reuses the pack shadow map when sun, view and world match. Off by default.": "Ҡояш, ҡараш һәм донъя тап килгәндә пакет күләгә картаһын ҡабаттан ҡуллана. Һүндерелгән по умолчанию.",
|
||||
"Find BlueMap": "Зәңгәр картаны табығыҙ",
|
||||
"On servers, finds their BlueMap web map for far terrain. Next join.": "Серверҙарҙа, алыҫ ерҙәр өсөн уларҙы BlueMap веб-картаһын таба. Киләһе ҡушылыу.",
|
||||
"BlueMap Radius": "Зәңгәр карта радиусы",
|
||||
"How far around you BlueMap tiles are downloaded. Next join.": "Һеҙҙең тирәләй ни тиклем алыҫ BlueMap плиталар скачать. Киләһе ҡушылыу.",
|
||||
"Synchronous": "Синхрон",
|
||||
"Asynchronous": "Ассинхрон",
|
||||
"Solid": "Ҡаты",
|
||||
"Solid Aggressive": "Ҡаты агрессив",
|
||||
"Hollow": "Ҡыуыш",
|
||||
"Leaves fully inside a canopy draw solid: fewer see-through layers.": "Япраҡтар тулыһынса навес эсендә ҡаты тарта: үтә күренмәле ҡатламдар аҙыраҡ.",
|
||||
"Leaves with one open side draw solid too: faster, chunkier edges.": "Япраҡтар менән бер асыҡ яғы ҡаты тарта ла: тиҙерәк, chunkier ситтәре.",
|
||||
"Drops faces between leaves: faster, but gaps look through.": "Япраҡтар араһында йөҙҙәрен тамсылай: тиҙерәк, әммә тишектәр аша ҡарай.",
|
||||
"Hotbar: Previous Slot": "Ҡыҙыу панелдә: Алдағы слот",
|
||||
"Hotbar: Next Slot": "Ҡыҙыу панелдә: Киләһе слот",
|
||||
"horizon.agent.connected.one": "Тоташтырылған: 1 агент тоташыуы",
|
||||
"horizon.agent.connected.many": "Тоташтырылған: %s агент тоташыуҙары",
|
||||
"horizon.agent.connected.one_ago": "Тоташтырылған: 1 агент тоташыу, һуңғы команда %s с элек",
|
||||
"horizon.agent.connected.many_ago": "Тоташтырылған: %s агент тоташыуҙары, һуңғы команда %s с элек",
|
||||
"horizon.agent.waiting": "Агент көтөп.",
|
||||
"horizon.agent.off": "Һүндерелгән: агенттар был уйынға етә алмай.",
|
||||
"horizon.agent.session_opened": "Был сессия өсөн уйынды башлаған программа асты.",
|
||||
"horizon.agent.socket": "Розетка: %s (уның тулы юлы өсөн реквизиттарҙы күсерергә)",
|
||||
"horizon.agent.local_only": "Урындағы ғына: был компьютерҙа агенттар, бер ҡасан да селтәр.",
|
||||
"%s nits": "%s нит",
|
||||
"Auto (%s nits)": "Авто (%s нит)",
|
||||
"%.2f nits": "%.2f нит",
|
||||
"Hides models behind opaque blocks. Entities update. Off with custom packs.": "Моделдәрҙе асыҡ булмаған блоктар артында йәшерә. Яңыртыу субъекттары. Ҡулланыусылар пакеттары менән өҙөлгән.",
|
||||
"horizon.extras.repro_keys": "Яҙма ярлыҡтар",
|
||||
"horizon.extras.repro_keys.tooltip": "F3+R репро яҙманы башлай йәки туҡтата һәм F3+E уның өйөмөн яҙа. Ғәҙәттәгесә һүндерелгән: яҙма донъяны күсерә.",
|
||||
"horizon.agent.record_session": "Яҙҙырыу сеансын башлау",
|
||||
"horizon.agent.record_stop": "Яҙҙырыуҙы туҡтатыу",
|
||||
"horizon.agent.export_repro": "Экспортлау Repro йыйылмаһы",
|
||||
"horizon.repro.started": "Яҙҙырыу башланды; F3+R уны туҡтата һәм өйөмдө яҙа.",
|
||||
"horizon.repro.stopped": "Яҙма туҡтатылды: %s",
|
||||
"horizon.repro.bundle": "Репро пакеты: %s",
|
||||
"horizon.repro.error": "Ҡабатлау: %s",
|
||||
"horizon.repro.no_recording": "Әлегә экспортҡа сығарырлыҡ яҙма юҡ.",
|
||||
"horizon.repro.replay_started": "Ҡабатлау башланды: %s",
|
||||
"horizon.pack.addInfo": "Modrinth ресурстар пакетын өҫтәү",
|
||||
"horizon.pack.addWorking": "Һорау Modrinth...",
|
||||
"horizon.pack.addNone": "Ресурс пакеттары табылмаған",
|
||||
"horizon.pack.addTitle": "Ресурстар пакетын өҫтәү",
|
||||
"horizon.pack.install": "Ҡуйыу",
|
||||
"horizon.pack.installing": "Ҡуйыу",
|
||||
"horizon.pack.installed": "Ҡуйылған",
|
||||
"horizon.pack.search": "Эҙләү",
|
||||
"horizon.pack.searchHint": "Эҙләү Modrinth...",
|
||||
"horizon.pack.filters": "Фильтрҙар",
|
||||
"horizon.pack.filter.realistic": "Ысынбарлыҡҡа ярашлы",
|
||||
"horizon.pack.filter.simplistic": "Ябайлаштырылған",
|
||||
"horizon.pack.filter.vanillaLike": "Ваниль һымаҡ",
|
||||
"horizon.pack.filter.x16": "16х",
|
||||
"horizon.pack.filter.x32": "32х",
|
||||
"horizon.pack.filter.x64": "64х",
|
||||
"horizon.pack.addFailed": "Пакетты өҫтәп булманы: %s",
|
||||
"horizon.extras.header.cosmetics": "Косметика",
|
||||
"horizon.extras.cosmetics_mine": "Минең косметика",
|
||||
"horizon.extras.cosmetics_mine.tooltip": "Йәшерен: һәр Horizon уйынсы һеҙҙең косметикаһыҙ күрә, һеҙ ҙә индерелгән. Шул уҡ переключатель стартер’s Гардероб.",
|
||||
"horizon.extras.cosmetics_others": "Башҡа уйынсыларҙың косметикаһы",
|
||||
"horizon.extras.cosmetics_others.tooltip": "Башҡа ниндәй Horizon уйынсылар кейә: барыһы ла, тик уларҙы исем биркаһы стилдәре, йәки бер нәмә лә. Йәшерен, уйын бер ҡасан да һорамай, улар нимә кейә.",
|
||||
"horizon.extras.cosmetics_auras": "Башҡаларҙың ауралары һәм эҙҙәре",
|
||||
"horizon.extras.cosmetics_auras.tooltip": "Аура һәм эҙҙәр башҡа уйынсылар кейә. Һүндерелгән по умолчанию.",
|
||||
"horizon.extras.cosmetics.shown": "Күрһәтелгән",
|
||||
"horizon.extras.cosmetics.hidden": "Йәшерен",
|
||||
"horizon.extras.cosmetics.name_tags": "Исем билдәләре генә"
|
||||
}
|
||||
@@ -0,0 +1,482 @@
|
||||
{
|
||||
"horizon.options.controller": "Кантралёр",
|
||||
"horizon.options.vibration": "Вібрацыя",
|
||||
"horizon.options.adaptive_triggers": "Адаптыўныя трыгеры",
|
||||
"horizon.options.lightbar": "Светлавая панэль",
|
||||
"horizon.options.look_sensitivity": "Адчувальнасць агляду",
|
||||
"horizon.options.invert_x": "Інверсія агляду па X",
|
||||
"horizon.options.invert_y": "Інверсія агляду па Y",
|
||||
"horizon.options.sneak_button": "Кнопка красціся",
|
||||
"horizon.options.move_deadzone": "Мёртвая зона руху",
|
||||
"horizon.options.look_deadzone": "Мёртвая зона агляду",
|
||||
"horizon.options.button_glyphs": "Гліфы кнопак",
|
||||
"horizon.options.on_screen_keyboard": "Экранная клавіятура",
|
||||
"horizon.options.chat_delay": "Затрымка чата",
|
||||
"horizon.options.lightbar.health": "здароўе",
|
||||
"horizon.options.lightbar.dimension": "Вымярэнне",
|
||||
"horizon.options.glyphs.auto": "Аўто",
|
||||
"horizon.options.keyboard.auto": "Аўто",
|
||||
"horizon.options.unavailable": "Гэтая функцыя яшчэ недаступная ў Horizon.",
|
||||
"horizon.options.search": "Налады пошуку...",
|
||||
"horizon.pages.mods": "Моды",
|
||||
"horizon.pages.shader_packs": "Пакеты шэйдараў",
|
||||
"horizon.pages.shader_options": "Параметры шэйдара",
|
||||
"horizon.pages.controller": "Налады кантролера",
|
||||
"horizon.pages.controller_binds": "Прывязкі кантролера",
|
||||
"horizon.pages.extras": "Horizon Дадаткова",
|
||||
"horizon.pages.settings": "Horizon Налады",
|
||||
"horizon.pages.agent": "Агент штучнага інтэлекту",
|
||||
"horizon.split.leave": "Сыходзь",
|
||||
"horizon.pages.split_settings": "Налады падзеленага экрана",
|
||||
"horizon.pages.split_profiles": "Хто гуляе?",
|
||||
"horizon.pages.split_setup": "Налада падзеленага экрана",
|
||||
"horizon.pages.music": "Музыка",
|
||||
"horizon.pages.music.menu": "Меню",
|
||||
"horizon.pages.music.overworld": "Надсвет",
|
||||
"horizon.pages.music.creative": "Творчы",
|
||||
"horizon.pages.music.underwater": "Пад вадой",
|
||||
"horizon.pages.music.end": "Канец",
|
||||
"horizon.pages.music.boss": "Бос",
|
||||
"horizon.pages.music.credits": "Крэдыты",
|
||||
"horizon.pages.music.overworld_biomes": "Сусветныя біёмы",
|
||||
"horizon.pages.music.nether_biomes": "Ніжнія біёмы",
|
||||
"horizon.pages.music.end_biomes": "Канчатковыя біёмы",
|
||||
"horizon.pages.music.other": "Іншая музыка",
|
||||
"horizon.pages.music.empty": "Няма музычных трэкаў: не загружаюцца гукі гульні.",
|
||||
"horizon.pages.music.tooltip": "Убудаваныя трэкі ў залежнасці ад сітуацыі: прайграйце адзін зараз або адключыце любы, каб гульня перастала яго выбіраць.",
|
||||
"horizon.pages.settings.tooltip": "Уласныя налады Horizon: графіка, кантролеры, дадатковыя функцыі і моды.",
|
||||
"horizon.pages.graphics.tooltip": "Простая графіка: кожная налада паказвае, колькі яна каштуе.",
|
||||
"horizon.pages.graphics_advanced.tooltip": "Кожная налада графікі, у тым ліку Horizon, з коштам кожнай.",
|
||||
"horizon.pages.controller.tooltip": "Кантролеры: іх кнопкі, стыкі, вібрацыя і навігацыя па меню.",
|
||||
"horizon.pages.extras.tooltip": "Неабавязковыя дадаткі, усе выключаны па змаўчанні: гульня застаецца яркай, пакуль вы не ўключыце адну.",
|
||||
"horizon.pages.agent.tooltip": "Дазвольце вашаму ўласнаму агенту штучнага інтэлекту гуляць: кліенты horizon-ctl і MCP на гэтым кампутары.",
|
||||
"horizon.pages.split_profiles.tooltip": "Хто гуляе: профіль захоўваецца ў гэтай тэчцы гульні.",
|
||||
"horizon.pages.split_setup.tooltip": "Вокны і маніторы, і хто дзе гуляе.",
|
||||
"horizon.pages.shader_packs.tooltip": "Пакеты шэйдараў з папкі shaderpacks: уласныя Horizon і тыя, якія знаходзяцца ў фармаце shaders/. Бяжыць адзін за адным.",
|
||||
"horizon.pages.mods.tooltip": "Моды, зробленыя для Horizon, з папкі horizon-mods. Кожны працуе ў пясочніцы і застаецца выключаным, пакуль вы яго не ўключыце.",
|
||||
"horizon.pages.open.graphics": "Графіка...",
|
||||
"horizon.pages.open.graphics_advanced": "Пашыраная графіка...",
|
||||
"horizon.pages.open.shader_packs": "Пакеты шэйдэраў...",
|
||||
"horizon.pages.open.controller": "Налады кантролера...",
|
||||
"horizon.pages.open.split_setup": "Раздзелены экран...",
|
||||
"horizon.pages.open.extras": "Дадаткова...",
|
||||
"horizon.pages.open.mods": "Моды...",
|
||||
"horizon.pages.open.agent": "Агент штучнага інтэлекту...",
|
||||
"horizon.pages.open.horizon_graphics": "Horizon Графіка...",
|
||||
"horizon.pages.open.controller_binds": "Кантролер прывязвае...",
|
||||
"horizon.pages.open.horizon_settings": "Horizon Налады...",
|
||||
"horizon.pages.open.music": "музыка...",
|
||||
"horizon.mods.empty": "Няма модаў: змясціце файлы .hmod у тэчку horizon-mods",
|
||||
"horizon.mods.stopped": " (Спынена)",
|
||||
"horizon.mods.not_built": " (Не пабудаваны)",
|
||||
"horizon.mods.settings": "Налады",
|
||||
"horizon.mods.in_world": " (пакінуць свет змяніцца)",
|
||||
"horizon.mods.open_folder": "Адкрыць тэчку Mod",
|
||||
"horizon.shader_packs.empty": "Пакетаў шэйдэраў няма: змесціце іх у тэчку шэйдэраў",
|
||||
"horizon.shader_options.open": "Параметры шэйдара...",
|
||||
"horizon.shader_options.profile": "Профіль",
|
||||
"horizon.shader_options.loading": "Чытанне параметраў пакета шэйдараў...",
|
||||
"horizon.agent.copy_details": "Скапіруйце звесткі аб падключэнні",
|
||||
"horizon.multiplayer.join": "Далучайцеся",
|
||||
"horizon.multiplayer.cancel_reconnecting": "Адмяніць паўторнае падключэнне",
|
||||
"horizon.multiplayer.join_friend": "Далучайцеся да сяброў",
|
||||
"horizon.multiplayer.invite_code": "Код запрашэння",
|
||||
"horizon.multiplayer.relay": "Рэле (неабавязкова)",
|
||||
"Preset": "Прадусталяваная",
|
||||
"LOD Distance": "LOD Адлегласць",
|
||||
"Far Detail": "Далёкая дэталь",
|
||||
"Cave Culling": "Выбракоўка пячор",
|
||||
"Entity Culling": "Выбракоўванне сутнасці",
|
||||
"Chunk Updates": "Абнаўленні чанка",
|
||||
"Upload Budget": "Бюджэт загрузкі",
|
||||
"Sky": "неба",
|
||||
"Fog": "Туман",
|
||||
"Weather": "Надвор'е",
|
||||
"Animated Textures": "Аніміраваныя тэкстуры",
|
||||
"Present Mode": "Рэжым сучаснасці",
|
||||
"Frame Pacing": "Тэмп кадраў",
|
||||
"Worker Threads": "Працоўныя тэмы",
|
||||
"Resolution Scale": "Шкала дазволу",
|
||||
"Anti-aliasing": "Згладжванне",
|
||||
"Upscaling": "Апскейлінг",
|
||||
"Paper White": "Папера белая",
|
||||
"Peak Brightness": "Пікавая яркасць",
|
||||
"Black Level": "Узровень чорнага",
|
||||
"UI Brightness": "Яркасць інтэрфейсу",
|
||||
"Battery Mode": "Рэжым батарэі",
|
||||
"Graphics API": "Графічны API",
|
||||
"Translucent Batching": "Напаўпразрысты дазаванне",
|
||||
"Performance Overlay": "Прадукцыйнасць Overlay",
|
||||
"Full Detail Distance": "Поўная адлегласць",
|
||||
"On": "Укл",
|
||||
"Off": "Выкл",
|
||||
"Unlimited": "Неабмежаваны",
|
||||
"Auto": "Аўто",
|
||||
"Custom": "Прыстасаваныя",
|
||||
"Performance": "Прадукцыйнасць",
|
||||
"Balanced": "Ураўнаважаны",
|
||||
"Quality": "Якасць",
|
||||
"Ultra": "Ультра",
|
||||
"Ultra Performance": "Ультрапрадукцыйнасць",
|
||||
"Native": "Натыўны",
|
||||
"Full": "Поўны",
|
||||
"Reduced": "Паменшаны",
|
||||
"Efficient": "Эфектыўная",
|
||||
"Precise": "Дакладны",
|
||||
"Auto (VSync)": "Аўта (VSync)",
|
||||
"Mailbox": "Паштовая скрыня",
|
||||
"Immediate": "Неадкладны",
|
||||
"FPS and Graph": "FPS і графік",
|
||||
"No cost": "Без выдаткаў",
|
||||
"Low cost": "Нізкі кошт",
|
||||
"Medium cost": "Сярэдні кошт",
|
||||
"High cost": "Высокі кошт",
|
||||
"Saves time": "Эканоміць час",
|
||||
"Graphics": "Графіка",
|
||||
"Done": "Гатова",
|
||||
"This feature is not yet available in Horizon.": "Гэтая функцыя яшчэ недаступная ў Horizon.",
|
||||
"Your display or system doesn't offer HDR output.": "Ваш дысплэй або сістэма не забяспечвае выхад HDR.",
|
||||
"Turn HDR on to use it.": "Уключыце HDR, каб выкарыстоўваць яго.",
|
||||
"Your GPU or graphics API doesn't support it.": "Ваш GPU або графічны API не падтрымлівае гэта.",
|
||||
"%s chunks": "%s кавалкаў",
|
||||
"%s per frame": "%s за кадр",
|
||||
"%s MiB/frame": "%s МіБ/кадр",
|
||||
"%s KiB/frame": "%s КіБ/кадр",
|
||||
"Auto (%s)": "Аўто (%s)",
|
||||
"Full-detail terrain range. LOD Distance can extend local worlds farther.": "Поўны дэталёвы дыяпазон мясцовасці. LOD Адлегласць можа пашырыць мясцовыя светы далей.",
|
||||
"Coarse distant terrain in local worlds. Integrated GPUs stop at 128 chunks.": "Грубая аддаленая мясцовасць у лакальных мірах. Убудаваныя графічныя працэсары спыняюцца на 128 кавалках.",
|
||||
"Reduced draws far terrain coarser: faster on this integrated GPU.": "Паменшанае малюнак больш грубай мясцовасці: хутчэй на гэтым убудаваным графічным працэсары.",
|
||||
"Reduced draws far terrain coarser, for GPUs it slows down.": "Зніжэнне малюе больш грубую мясцовасць, для графічных працэсараў гэта запавольваецца.",
|
||||
"Field of view. Wider shows more terrain at once.": "Поле зроку. Шырэй паказвае адразу больш мясцовасці.",
|
||||
"Caps frames per second; a cap saves power and heat.": "Колькасць кадраў у секунду; шапка эканоміць энергію і цяпло.",
|
||||
"Waits for the display's refresh: no tearing, a little latency.": "Чакае абнаўлення дысплея: без разрыву, з невялікай затрымкай.",
|
||||
"Size of menus and the HUD.": "Памер меню і HUD.",
|
||||
"Sets the options below together. Changing one makes it Custom.": "Разам усталёўвае параметры ніжэй. Змена аднаго робіць яго карыстальніцкім.",
|
||||
"Lava, fire and sunlight shine brighter than white. Needs an HDR display.": "Лава, агонь і сонечнае святло ззяюць ярчэй белага. Патрэбен дысплей HDR.",
|
||||
"Your display's darkest black. 0 for OLED; LCDs glow a little.": "Самы цёмны чорны на вашым дысплеі. 0 для OLED; ВК-дысплеі трохі свецяцца.",
|
||||
"How bright highlights get. Auto: the peak your system reports.": "Якія яркія моманты становяцца. Аўта: пік, пра які паведамляе ваша сістэма.",
|
||||
"How bright white paper and menus look. Auto: your desktop's white.": "Як ярка выглядаюць белая папера і меню. Аўтаматычна: ваш працоўны стол белы.",
|
||||
"How bright the HUD and menus are, against paper white.": "Наколькі яркія HUD і меню на фоне белай паперы.",
|
||||
"How far mobs, crops and machines keep working. CPU time.": "Як далёка працягваюць працаваць мобы, ураджай і машыны. працэсарны час.",
|
||||
"How far away mobs and items are drawn, as a share of normal.": "Наколькі далёка намаляваны мобы і прадметы ў долі звычайнага.",
|
||||
"Skips terrain hidden behind closed sections. Off costs a lot.": "Прапускае мясцовасць, схаваную за закрытымі ўчасткамі. Off каштуе шмат.",
|
||||
"Hides entities behind opaque blocks.": "Хавае аб'екты за непразрыстымі блокамі.",
|
||||
"No entity occlusion culling.": "Няма выбракоўвання аклюзіі сутнасці.",
|
||||
"CPU occlusion test runs this frame.": "Тэст аклюзіі ЦП запускае гэты кадр.",
|
||||
"Occlusion checks run on a worker thread.": "Праверкі аклюзіі выконваюцца ў працоўным патоку.",
|
||||
"Meshed sections uploaded per frame. Lower is smoother while loading.": "Сеткавыя раздзелы, загружаныя на кадр. Ніжняя больш плыўная падчас загрузкі.",
|
||||
"Soft shadows in corners. Costs chunk building time only.": "Мяккія цені ў кутах. Каштуе толькі час зборкі кавалкаў.",
|
||||
"Smaller copies of block textures for distant terrain: less shimmer.": "Меншыя копіі блочных тэкстур для далёкай мясцовасці: менш мігацення.",
|
||||
"Blends grass and water colours across biomes when building chunks.": "Змешвае колеру травы і вады ў біёмах пры стварэнні кавалкаў.",
|
||||
"Cloud layer: off, flat (fast) or 3D (fancy).": "Воблачны пласт: выключаны, плоскі (хуткі) або 3D (фантастычны).",
|
||||
"How far clouds reach, in chunks.": "Наколькі дасягаюць воблакі, кавалкамі.",
|
||||
"Draws the sky, sun, moon and stars.": "Малюе неба, сонца, месяц і зоркі.",
|
||||
"Distance fog. Off shows the edge of the loaded world.": "Далёкі туман. Off паказвае край загружанага свету.",
|
||||
"Draws rain and snow.": "Малюе дождж і снег.",
|
||||
"How far rain and snow fall around you.": "Як далёка вакол цябе дождж і снег.",
|
||||
"How many particles effects spawn.": "Колькі эфектаў часціц спараджае.",
|
||||
"Round shadows under mobs and items.": "Круглыя цені пад мобамі і прадметамі.",
|
||||
"Leaves with see-through gaps. Off draws them solid.": "Лісце з празрыстымі прасветамі. Off малюе іх цвёрда.",
|
||||
"Sorts water and glass more exactly behind each other.": "Сартуе ваду і шкло больш дакладна адзін за адным.",
|
||||
"Which chunk rebuilds wait for the frame: none, nearby or yours.": "Які кавалак перабудоўваецца ў чаканні кадра: ніякі, побач ці ваш.",
|
||||
"Animates water, lava, fire and other moving textures.": "Ажыўляе ваду, лаву, агонь і іншыя рухомыя тэкстуры.",
|
||||
"World pixels per screen pixel. Below 100% is faster on the GPU.": "Сусветныя пікселі на піксель экрана. Ніжэй за 100% хутчэй на графічным працэсары.",
|
||||
"Smooths jagged edges. FXAA: softer. TAA: smoothest, moving things may trail.": "Згладжвае няроўныя краю. FXAA: мякчэй. TAA: самыя гладкія рэчы, якія рухаюцца, могуць цягнуцца.",
|
||||
"Renders the world smaller and rebuilds it with TAA. Faster, softer.": "Памяншае свет і перабудоўвае яго з TAA. Хутчэй, мякчэй.",
|
||||
"HDR output on an HDR display: lava, fire and sunlight shine brighter.": "Вывад HDR на дысплеі HDR: лава, агонь і сонечнае святло ззяюць ярчэй.",
|
||||
"How frames reach the screen while VSync is off.": "Як кадры трапляюць на экран, калі VSync выключаны.",
|
||||
"Efficient sleeps until the next frame; Precise spins, like vanilla.": "Эфектыўнае спіць да наступнага кадра; Дакладныя спіны, як ваніль.",
|
||||
"Fills the screen (borderless).": "Запаўняе экран (без палёў).",
|
||||
"Brightens dark places.": "Асвятляе цёмныя месцы.",
|
||||
"Lowers the frame rate when minimised, or idle too.": "Зніжае частату кадраў пры згортванні або ў рэжыме чакання.",
|
||||
"Sways the view while walking.": "Качае погляд падчас хады.",
|
||||
"Fades newly loaded chunks in.": "Змяншае толькі што загружаныя кавалкі.",
|
||||
"Darkens the screen's edges.": "Зацямняе краю экрана.",
|
||||
"Shows when the world saves.": "Паказвае, калі свет ратуе.",
|
||||
"Shows attack cooldown.": "Паказвае час аднаўлення атакі.",
|
||||
"60 FPS cap (30 in menus or unfocused), half the workers: less power.": "Абмежаванне 60 кадраў у секунду (30 у меню або без увагі), палова рабочых: меншая магутнасць.",
|
||||
"Threads that generate, light and mesh chunks. Next start.": "Ніткі, якія ствараюць, лёгкія і сеткаватыя кавалкі. Наступны старт.",
|
||||
"Vulkan, then DirectX 12 (Windows) or OpenGL (Linux) where it fails. Next start.": "Vulkan, затым DirectX 12 (Windows) або OpenGL (Linux), дзе не атрымліваецца. Наступны старт.",
|
||||
"Water and glass in one buffer: fewer draw calls, a bit more VRAM. Next start.": "Вада і шкло ў адным буферы: менш выклікаў на розыгрыш, крыху больш VRAM. Наступны старт.",
|
||||
"Mesh data sent to the GPU per frame. Lower is smoother while loading.": "Даныя сеткі, якія адпраўляюцца ў графічны працэсар за кадр. Ніжняя больш плыўная падчас загрузкі.",
|
||||
"Frame rate and frame times over the game, with a graph.": "Частата кадраў і час кадраў у гульні з графікам.",
|
||||
"horizon.multiplayer.finding_friend": "Пошук свету вашага сябра...",
|
||||
"horizon.multiplayer.not_signed_in": "Гэты сервер знаходзіцца ў онлайн-рэжыме. Увайдзіце ў свой уліковы запіс Microsoft у праграме запуску Horizon, каб далучыцца да яе.",
|
||||
"horizon.multiplayer.invalid_address": "Няправільны адрас сервера: %s",
|
||||
"horizon.multiplayer.connected_friend_direct": "Падключаны непасрэдна да вашага сябра...",
|
||||
"horizon.multiplayer.connected_friend_relay": "Падключаны да вашага сябра праз рэле...",
|
||||
"General": "Генерал",
|
||||
"Advanced": "Пашыраны",
|
||||
"Undo": "Адмяніць",
|
||||
"Search options": "Параметры пошуку",
|
||||
"Shortcut": "Ярлык",
|
||||
"Distance": "Дыстанцыя",
|
||||
"Display": "Дысплей",
|
||||
"Interface": "Інтэрфейс",
|
||||
"Sky and weather": "Неба і надвор'е",
|
||||
"Lighting and entities": "Асвятленне і сутнасці",
|
||||
"Textures": "Тэкстуры",
|
||||
"Image": "Малюнак",
|
||||
"Chunk loading": "Загрузка чанка",
|
||||
"Culling": "Выбракоўка",
|
||||
"Power": "Магутнасць",
|
||||
"Frames": "Рамкі",
|
||||
"Overlay": "Накладка",
|
||||
"Output": "Выхад",
|
||||
"Brightness": "Яркасць",
|
||||
"How far you see, the window and the HUD.": "Як далёка вы бачыце, акно і HUD.",
|
||||
"The sky and weather, lighting, textures and the image.": "Неба і надвор'е, асвятленне, тэкстуры і малюнак.",
|
||||
"Chunk loading, culling and power use.": "Загрузка кавалкаў, выбракоўванне і выкарыстанне энергіі.",
|
||||
"How frames reach the screen, and the performance overlay.": "Як кадры трапляюць на экран і накладанне прадукцыйнасці.",
|
||||
"Brighter-than-white output on an HDR display.": "Ярчэйшы за белы выхад на HDR-дысплеі.",
|
||||
"Results for \"%s\"": "Вынікі для \"%s\"",
|
||||
"No settings match.": "Налады не супадаюць.",
|
||||
"horizon.title.not_affiliated": "Не звязаны з Mojang або Microsoft",
|
||||
"horizon.extras.header.lighting": "Асвятленне",
|
||||
"horizon.extras.header.third_person": "Трэцяя асоба",
|
||||
"horizon.extras.header.particles": "Часціцы",
|
||||
"horizon.extras.header.inventory": "Інвентар",
|
||||
"horizon.extras.header.chat": "Чат",
|
||||
"horizon.extras.header.multiplayer": "Мультыплэер",
|
||||
"horizon.extras.header.sound": "Гук",
|
||||
"horizon.extras.header.menus": "Меню",
|
||||
"horizon.extras.fullbright": "Фулбрайт",
|
||||
"horizon.extras.dynamic_lights": "Дынамічныя фары",
|
||||
"horizon.extras.own_name_tag": "Уласная бірка з імем",
|
||||
"horizon.extras.hide_block_particles": "Схаваць часціцы, якія разбіваюць блок",
|
||||
"horizon.extras.auto_reconnect": "Аўтаматычнае падключэнне",
|
||||
"horizon.extras.ui_sound_reserve": "Захоўвайце каналы для гукаў інтэрфейсу",
|
||||
"horizon.extras.music_page": "Музычная старонка",
|
||||
"horizon.extras.mouse_tweaks": "Элементы кіравання Mouse Tweaks",
|
||||
"horizon.extras.mouse_tweaks_wheel": "Кола пракруткі перамяшчае элементы",
|
||||
"horizon.extras.sort": "Кнопкі сартавання",
|
||||
"horizon.extras.sort_key": "Ключ сартавання",
|
||||
"horizon.extras.agent_control": "Агентскі кантроль",
|
||||
"horizon.extras.splitscreen": "Раздзелены экран",
|
||||
"horizon.extras.chat_animation": "Плаўны чат",
|
||||
"horizon.extras.chat_indicator": "Індыкатар паведамлення",
|
||||
"horizon.extras.wheel_cycles_settings": "Кола пракруткі змяняе налады",
|
||||
"horizon.extras.pack_browser": "Браўзэр Resource Pack",
|
||||
"horizon.extras.fullbright.tooltip": "Паказвайце блокі і аб'екты пры поўным асвятленні, нават у цёмных месцах.",
|
||||
"horizon.extras.dynamic_lights.tooltip": "Факелы і іншыя крыніцы святла, якія трымаюць, упускаюць або гараць, асвятляюць блокі вакол іх.",
|
||||
"horizon.extras.own_name_tag.tooltip": "Паказвае ваша імя над галавой ад трэцяй асобы, як яго бачаць іншыя гульцы. Схаваны, калі сервер хавае назвы вашай каманды або вы нябачныя.",
|
||||
"horizon.extras.hide_block_particles.tooltip": "Хавае часціцы смецця, якія вырываюцца з разбітага блока і рассыпаюцца на той, які вы здабываеце. Іншыя часціцы застаюцца.",
|
||||
"horizon.extras.auto_reconnect.tooltip": "Паўторна далучаецца да сервера пасля страты злучэння або перазагрузкі, ніколі пасля кіку або забароны.",
|
||||
"horizon.extras.ui_sound_reserve.tooltip": "Гукі ў свеце пакідаюць 16 з 247 гукавых каналаў свабоднымі, таму іх паток (вялікі выбух) не можа заглушыць націсканне меню.",
|
||||
"horizon.extras.music_page.tooltip": "«Музыка і гукі» атрымлівае старонку «Музыка...»: прайграйце любы ўбудаваны трэк зараз або адключыце адзін, каб гульня перастала яго выбіраць. Нічога не зменіцца, пакуль вы не адключыце трэк.",
|
||||
"horizon.extras.mouse_tweaks.tooltip": "Перацягванне правай кнопкай мышы змяшчае па адным у слот, перацягванне левай кнопкай збірае ўтрымоўваны прадмет, Shift + перацягванне левай кнопкай мышы перамяшчае кожны слот.",
|
||||
"horizon.extras.mouse_tweaks_wheel.tooltip": "Уніз адпраўляе адзін элемент слота на другі бок, уверх вяртае адзін назад.",
|
||||
"horizon.extras.sort.tooltip": "Сартуе інвентар, куфры, бочкі, эндэрскія куфры і шулкерныя скрыні ў творчым парадку ўкладак, аб'ядноўваючы стосы.",
|
||||
"horizon.extras.sort_key.tooltip": "Сартуе частку пад курсорам. Націсніце, затым націсніце клавішу; Уцёкі развязвае яго.",
|
||||
"horizon.extras.no_ai.tooltip": "Хавае і адключае ўсе функцыі штучнага інтэлекту: кіраванне агентамі, horizon-ctl і серверы MCP. Пераключальнік пускавы ўстаноўкі таксама.",
|
||||
"horizon.extras.agent_control.tooltip": "Ваш уласны агент штучнага інтэлекту можа гуляць у гэтую гульню праз horizon-ctl або кліент MCP толькі на гэтым камп'ютары.",
|
||||
"horizon.extras.discord_presence.tooltip": "Паказвае Playing Horizon у вашым профілі Discord падчас запуску Discord: меню, адзіночны або шматкарыстальніцкі рэжым, памер і час гульні. Ніколі не назва свету або адрас сервера.",
|
||||
"Calibrate...": "Адкалібраваць...",
|
||||
"Calibrate Anyway...": "Усё роўна адкалібраваць...",
|
||||
"Use Automatic Setup": "Выкарыстоўвайце аўтаматычную наладу",
|
||||
"Shortcut: %s": "Ярлык: %s",
|
||||
"Next": "Далей",
|
||||
"HDR Calibration %s/%s: %s": "Каліброўка HDR %s/%s: %s",
|
||||
"Sets the three below full screen, one test picture at a time.": "Устанаўлівае тры ніжэй на ўвесь экран, па адным тэставым малюнку.",
|
||||
"A key that opens this screen from the game. Not bound at first.": "Ключ, які адкрывае гэты экран з гульні. Спачатку не звязаны.",
|
||||
"Your display didn't say how bright it gets: calibrate to set it up.": "На вашым дысплеі не пазначана, наколькі ён яркім: адкалібруйце, каб наладзіць яго.",
|
||||
"Already set up for your display. Only calibrate if HDR looks wrong.": "Ужо наладжана для вашага дысплея. Калібруйце, толькі калі HDR выглядае няправільна.",
|
||||
"Puts Peak Brightness and Paper White back to your display's setup.": "Вяртае пікавую яркасць і папяровы белы ў налады вашага дысплея.",
|
||||
"Set up for your display. Leave on Auto unless it looks wrong.": "Наладзьце для вашага дысплея. Пакіньце на Auto, калі гэта не выглядае няправільна.",
|
||||
"Lower it until the logo just disappears into the black.": "Апускайце яго, пакуль лагатып проста не знікне ў чорным колеры.",
|
||||
"Raise it until the logo just disappears into the bright square.": "Падымайце яго, пакуль лагатып не знікне ў яркім квадраце.",
|
||||
"Make the card a white that's comfortable to look at for a long time, in the light you play in.": "Зрабіце карту белай, каб на яе было зручна глядзець на працягу доўгага часу пры святле, пры якім вы гуляеце.",
|
||||
"horizon.splitscreen.profiles.forget": "Забыць",
|
||||
"horizon.splitscreen.profiles.create": "Ствараць",
|
||||
"horizon.splitscreen.profiles.you": " - вы",
|
||||
"horizon.splitscreen.profiles.forget_named": "Забыць %s",
|
||||
"horizon.splitscreen.profiles.previous": "Папярэдні",
|
||||
"horizon.splitscreen.profiles.next": "Далей",
|
||||
"horizon.splitscreen.profiles.new_button": "Новы профіль...",
|
||||
"horizon.splitscreen.profiles.forget_title": "Забыць профіль?",
|
||||
"horizon.splitscreen.profiles.forget_leaves": "Ён пакідае спіс гэтага экземпляра.",
|
||||
"horizon.splitscreen.profiles.forget_kept": "Сусветны прагрэс і налады захоўваюцца.",
|
||||
"horizon.splitscreen.profiles.new_title": "Новы профіль",
|
||||
"horizon.splitscreen.profiles.name_hint": "Імя (ад 3 да 16 літар, лічбаў, _)",
|
||||
"horizon.splitscreen.profiles.switch_title": "Пераключыць профіль",
|
||||
"horizon.splitscreen.profiles.offline_note": "Афлайн-профілі належаць да гэтага асобніка",
|
||||
"horizon.splitscreen.profiles.move": "Рухайцеся туды, дзе гуляеце",
|
||||
"horizon.splitscreen.profiles.move_place": "Рухайцеся туды, дзе вы гуляеце: %s",
|
||||
"horizon.friends.title": "Гуляць з сябрамі",
|
||||
"horizon.friends.hint": "Сябры ўстаўце код пасля кнопкі \"Сябры\" на тытульным экране ў раздзеле \"Прамое злучэнне\" або на старонцы \"Прайграванне\" праграмы запуску.",
|
||||
"horizon.friends.copied": "Скапіравана",
|
||||
"horizon.friends.copy_code": "Скапіруйце код",
|
||||
"horizon.friends.stop_sharing": "Спыніць абагульванне",
|
||||
"horizon.friends.none_yet": "Тут пакуль няма сяброў.",
|
||||
"horizon.friends.here_now": "Вось зараз: %s",
|
||||
"horizon.friends.share_intro": "Падзяліцеся гэтым светам за кодам запрашэння: ён адкрываецца ў лакальнай сеткі, і сябры ў Інтэрнэце далучаюцца з кодам. Наш сервер не задзейнічаны.",
|
||||
"horizon.friends.start_sharing": "Пачніце абагульваць",
|
||||
"horizon.friends.troubleshooting": "Ліквідацыя непаладак...",
|
||||
"horizon.friends.stopped": "Абагульванне кода запрашэння спынена.",
|
||||
"horizon.friends.short_code_changed": "Хтосьці спрабаваў увесці няправільны кароткі код, таму ён змяніўся.",
|
||||
"horizon.friends.wrong_code": "Хтосьці паспрабаваў увесці няправільны код.",
|
||||
"horizon.friends.code_ready": "Ваш код запрашэння гатовы: меню гульні, гульня з сябрамі. Скапіруйце яго і адпраўце сваім сябрам.",
|
||||
"horizon.friends.share_failed": "Не атрымалася падзяліцца светам: %s",
|
||||
"horizon.friends.finding_route": "Пошук, як сябры могуць звязацца з вамі...",
|
||||
"horizon.osk.shift": "зрух",
|
||||
"horizon.osk.space": "космас",
|
||||
"horizon.osk.delete": "Выдаліць",
|
||||
"horizon.osk.type": "Тып",
|
||||
"horizon.osk.symbols": "Сімвалы",
|
||||
"horizon.osk.close": "Блізка",
|
||||
"horizon.extras.chat_animation.tooltip": "Новы радок чата слізгае злева, пакуль ён знікае, замест таго, каб выглядаць цалкам.",
|
||||
"horizon.extras.chat_indicator.tooltip": "Каляровая паласа злева ад радка чата.",
|
||||
"horizon.extras.wheel_cycles_settings.tooltip": "Кола пракруткі над кнопкай у наладах змяняе яе значэнне, як у vanilla. Выключана, кола толькі пракручвае спіс.",
|
||||
"horizon.extras.pack_browser.tooltip": "Select Resource Packs атрымлівае кнопку «Дадаць», якая выконвае пошук у Modrinth і ўсталёўвае пакет у вашу тэчку пакетаў. Выключана, гульня ніколі не звязваецца з Modrinth.",
|
||||
"horizon.extras.splitscreen.tooltip": "У свеце іншы кантролер можа далучыцца як новы гулец: націсніце A, калі ён запытае, затым выберыце профіль і дзе гуляць.",
|
||||
"horizon.splitscreen.setup.monitor": "Манітор %s",
|
||||
"horizon.splitscreen.setup.monitor_unknown": "манітор",
|
||||
"horizon.splitscreen.setup.window": "Акно %s",
|
||||
"horizon.splitscreen.setup.new_window": "Новае акно",
|
||||
"horizon.splitscreen.setup.fill_monitor": "Запоўніце %s",
|
||||
"horizon.splitscreen.setup.done": "Гатова",
|
||||
"horizon.splitscreen.setup.on": "Укл",
|
||||
"horizon.splitscreen.setup.off": "Выкл",
|
||||
"horizon.splitscreen.setup.player": "Гулец %s",
|
||||
"horizon.splitscreen.setup.revert": "Вярнуць",
|
||||
"horizon.splitscreen.setup.apply": "Ужыць",
|
||||
"horizon.splitscreen.setup.warning.empty_main": "Ніхто не гуляе ў Window 1: яна хаваецца",
|
||||
"horizon.splitscreen.setup.warning.empty_close": "Ніхто не гуляе ў Window %s: яно зачыняецца пры ўжыванні",
|
||||
"horizon.splitscreen.setup.warning.empty_new": "Ніхто не гуляе ў Window %s: яно не адчыняецца",
|
||||
"horizon.splitscreen.setup.warning.on_main": "Window %s запаўняе манітор Window 1: яго гульцы гуляюць у Window 1",
|
||||
"horizon.splitscreen.setup.warning.unplugged": "Манітор Window %s не падключаны: яго гульцы гуляюць у Window 1",
|
||||
"horizon.splitscreen.setup.status.off": "Splitscreen выключаны.",
|
||||
"horizon.splitscreen.setup.status.enable_hint": "Уключыце яго, затым націсніце кнопку на іншым кантролеры ў свеце.",
|
||||
"horizon.splitscreen.setup.status.join_hint": "Націсніце A, каб далучыцца і выбраць профіль.",
|
||||
"horizon.splitscreen.setup.status.idle": "Раздзелены экран у рэжыме чакання",
|
||||
"horizon.splitscreen.setup.status.alone": "Няма іншых мясцовых гульцоў.",
|
||||
"horizon.splitscreen.setup.status.solo_controls": "Індывідуальныя элементы кіравання і зваротная сувязь кантролера не змяніліся.",
|
||||
"horizon.splitscreen.setup.window_empty": "Акно %s: пустое",
|
||||
"horizon.splitscreen.setup.note.select": "Пстрыкніце прайгравальнік або перацягніце яго ў акно або на манітор.",
|
||||
"horizon.splitscreen.setup.note.apply": "Падайце заяўку, каб гуляць такім чынам, вярніце, каб адмяніць.",
|
||||
"horizon.splitscreen.setup.note.place": "Дзе гуляць %s?",
|
||||
"horizon.splitscreen.setup.this_player": "гэты гулец",
|
||||
"horizon.splitscreen.setup.switch_disabled": "Раздзелены экран выключаецца, як толькі іншыя сыдуць (іх меню паўзы).",
|
||||
"horizon.splitscreen.setup.window_place": "Акно %s (%s з %s)",
|
||||
"horizon.splitscreen.setup.names": "Імёны",
|
||||
"horizon.splitscreen.setup.identify": "Ідэнтыфікаваць",
|
||||
"horizon.splitscreen.setup.layout.two": "2 абмен: %s",
|
||||
"horizon.splitscreen.setup.layout.three": "3 абмен: %s",
|
||||
"horizon.splitscreen.setup.layout.two.0": "Аўто",
|
||||
"horizon.splitscreen.setup.layout.two.1": "Бок аб бок",
|
||||
"horizon.splitscreen.setup.layout.two.2": "Зверху і знізу",
|
||||
"horizon.splitscreen.setup.layout.three.0": "Адзін шырокі зверху",
|
||||
"horizon.splitscreen.setup.layout.three.1": "Адзін высокі злева",
|
||||
"horizon.splitscreen.setup.layout.three.2": "Бок аб бок",
|
||||
"horizon.splitscreen.setup.help.player": "Націсніце або перацягніце %s, каб перамясціць іх.",
|
||||
"horizon.splitscreen.setup.help.layout_auto": "%s (побач, калі акно шырокае). Націсніце, каб змяніць.",
|
||||
"horizon.splitscreen.setup.help.layout": "%s. Націсніце, каб змяніць.",
|
||||
"horizon.splitscreen.setup.help.switch": "Splitscreen для гэтага кампутара, уключаны або выключаны.",
|
||||
"horizon.splitscreen.setup.help.identify": "Погляд кожнага гульца паказвае, у якім акне ён знаходзіцца.",
|
||||
"horizon.splitscreen.setup.help.names": "Імя кожнага гульца ў куце іх агляду.",
|
||||
"horizon.splitscreen.setup.help.revert": "Адмяніць яшчэ не прымененыя змены.",
|
||||
"horizon.splitscreen.setup.help.apply": "Гуляйце так, як паказвае карта.",
|
||||
"horizon.splitscreen.setup.help.unchanged": "Пакуль нічога не змянілася.",
|
||||
"horizon.splitscreen.setup.give_up_pad": "Адмоўцеся ад Pad",
|
||||
"horizon.splitscreen.prompt.controller_connected": "Кантролер падключаны",
|
||||
"horizon.splitscreen.prompt.controller_disconnected": "Кантролер адключаны",
|
||||
"horizon.splitscreen.prompt.controller_disconnected.hint": "Зноў падключыце яго або націсніце кнопку на іншым",
|
||||
"horizon.splitscreen.prompt.join.one": "%s хоча далучыцца",
|
||||
"horizon.splitscreen.prompt.join.many": "%s кантралёраў хочуць далучыцца",
|
||||
"horizon.splitscreen.prompt.join.yes": "Далучайцеся",
|
||||
"horizon.splitscreen.prompt.join.as_p1": "Гуляць як P1",
|
||||
"horizon.splitscreen.prompt.join.no": "няма",
|
||||
"horizon.splitscreen.prompt.lost": "%s: кантролер адключаны",
|
||||
"horizon.splitscreen.prompt.lost.use_another": "Выкарыстоўвайце іншы",
|
||||
"horizon.splitscreen.prompt.lost.leave": "Сыходзь",
|
||||
"horizon.splitscreen.setup.help.give_up_pad": "Ваш кантролер перастае кіраваць вамі і прапануе далучыцца (A).",
|
||||
"horizon.splitscreen.setup.note.held_at": "%s да %s: А кідае яго сюды, Б ставіць назад.",
|
||||
"horizon.splitscreen.setup.note.held": "%s падняў: левы/правы выбіраюць, дзе, А кідае, Б ставіць назад.",
|
||||
"Hides models behind opaque blocks. Async checks off-thread; entities tick.": "Хавае мадэлі за непразрыстымі блокамі. Async правярае па-за патокам; суб'ектаў цік.",
|
||||
"Block Entities": "Блокавыя аб'екты",
|
||||
"Shulker Boxes": "Скрынкі Шулкера",
|
||||
"Reuses settled boxes; lid movement stays animated.": "Паўторна выкарыстоўвае адстойнікі; рух вечка застаецца ажыўленым.",
|
||||
"Signs": "Знакі",
|
||||
"Reuses sign text until text, light, or font changes.": "Паўторна выкарыстоўвае тэкст знака, пакуль не зменіцца тэкст, падсвятленне або шрыфт.",
|
||||
"Decorated Pots": "Упрыгожаныя гаршкі",
|
||||
"Reuses still pots; break wobble and sherd changes redraw.": "Паўторна выкарыстоўвае гаршкі; перапыніць хістанне і асколак змены перамаляваць.",
|
||||
"Bells": "Званы",
|
||||
"Reuses still bells; ringing stays animated.": "Паўторна выкарыстоўвае яшчэ званы; званок застаецца аніміраваным.",
|
||||
"Chests": "Сундукі",
|
||||
"Reuses closed chests; moving lids stay animated.": "Паўторна выкарыстоўвае закрытыя куфры; рухомыя павекі застаюцца ажыўленымі.",
|
||||
"Banners": "Банеры",
|
||||
"Reuses poles; flags and pattern layers still update.": "Паўторна выкарыстоўвае слупы; сцягі і ўзоры слаёў па-ранейшаму абнаўляюцца.",
|
||||
"Copper Golem Statues": "Медныя статуі голема",
|
||||
"Reuses statue geometry until its block state changes.": "Паўторна выкарыстоўвае геаметрыю статуі, пакуль не зменіцца яе стан блока.",
|
||||
"Leaf Culling": "Выбракоўванне лісця",
|
||||
"Every leaf face. Vanilla's fancy leaves.": "Кожны ліст твар. Вострыя лісце ванілі.",
|
||||
"Distant Plant Dither": "Дыстантны завод",
|
||||
"Keeps fine plants in high-res packs from fading far away.": "Захоўвае выдатныя расліны ў пакетах з высокім дазволам ад выцвітання.",
|
||||
"Screenshot Quality": "Якасць скрыншота",
|
||||
"F2 screenshots at this many times the game's resolution. Higher takes longer.": "Скрыншоты F2 з дазволам, які шмат разоў перавышае дазвол гульні. Вышэйшы займае больш часу.",
|
||||
"Frame Generation": "Генерацыя фрэймаў",
|
||||
"Shows a made-up frame between each two real ones: smoother, a little more lag.": "Паказвае прыдуманую рамку паміж двума сапраўднымі: больш гладкая, з крыху большым адставаннем.",
|
||||
"Shadow Cache": "Ценявы кэш",
|
||||
"Reuses the pack shadow map when sun, view and world match. Off by default.": "Паўторна выкарыстоўвае карту ценяў зграі, калі сонца, выгляд і свет супадаюць. Выключана па змаўчанні.",
|
||||
"Find BlueMap": "Знайдзіце BlueMap",
|
||||
"On servers, finds their BlueMap web map for far terrain. Next join.": "На серверах знаходзіць вэб-карту BlueMap для далёкай мясцовасці. Далей далучыцца.",
|
||||
"BlueMap Radius": "Радыус BlueMap",
|
||||
"How far around you BlueMap tiles are downloaded. Next join.": "Як далёка вакол вас загружаюцца пліткі BlueMap. Далей далучыцца.",
|
||||
"Synchronous": "Сінхронныя",
|
||||
"Asynchronous": "Асінхронны",
|
||||
"Solid": "Цвёрды",
|
||||
"Solid Aggressive": "Суцэльны агрэсіўны",
|
||||
"Hollow": "Полая",
|
||||
"Leaves fully inside a canopy draw solid: fewer see-through layers.": "Лісце цалкам унутры полага малююць суцэльна: менш празрыстых слаёў.",
|
||||
"Leaves with one open side draw solid too: faster, chunkier edges.": "Лісце з адным адкрытым бокам таксама атрымліваюцца цвёрдымі: больш хуткія, каржакаватыя краю.",
|
||||
"Drops faces between leaves: faster, but gaps look through.": "Апускае грані паміж лісцікамі: хутчэй, але шчыліны праглядваюць.",
|
||||
"Hotbar: Previous Slot": "Гарачая панэль: папярэдні слот",
|
||||
"Hotbar: Next Slot": "Гарачая панэль: наступны слот",
|
||||
"horizon.agent.connected.one": "Падключана: 1 падключэнне агента",
|
||||
"horizon.agent.connected.many": "Падключана: %s агентскіх злучэнняў",
|
||||
"horizon.agent.connected.one_ago": "Падключана: 1 падключэнне агента, апошняя каманда %s с таму",
|
||||
"horizon.agent.connected.many_ago": "Падключана: %s злучэнняў агента, апошняя каманда %s с таму",
|
||||
"horizon.agent.waiting": "Чакаю агента.",
|
||||
"horizon.agent.off": "Выключана: агенты не могуць атрымаць доступ да гэтай гульні.",
|
||||
"horizon.agent.session_opened": "Адкрыты для гэтай сесіі праграмай, якая запусціла гульню.",
|
||||
"horizon.agent.socket": "Сокет: %s (скапіруйце дэталі для поўнага шляху)",
|
||||
"horizon.agent.local_only": "Толькі лакальна: агенты на гэтым кампутары, ніколі ў сетцы.",
|
||||
"%s nits": "%s ніт",
|
||||
"Auto (%s nits)": "Аўта (%s ніт)",
|
||||
"%.2f nits": "%.2f ніт",
|
||||
"Hides models behind opaque blocks. Entities update. Off with custom packs.": "Хавае мадэлі за непразрыстымі блокамі. Абнаўленне суб'ектаў. Выключыце спецыяльныя пакеты.",
|
||||
"horizon.extras.repro_keys": "Ярлыкі для запісу",
|
||||
"horizon.extras.repro_keys.tooltip": "F3+R запускае або спыняе прайгравальны запіс, а F3+E запісвае пакет. Выключана па змаўчанні: запіс капіруе свет.",
|
||||
"horizon.agent.record_session": "Пачаць сеанс запісу",
|
||||
"horizon.agent.record_stop": "Спыніць сеанс запісу",
|
||||
"horizon.agent.export_repro": "Экспарт Repro Bundle",
|
||||
"horizon.repro.started": "Запіс пачаўся; F3+R спыняе яго і запісвае пакет.",
|
||||
"horizon.repro.stopped": "Запіс спынены: %s",
|
||||
"horizon.repro.bundle": "Пакет рэпрадукцый: %s",
|
||||
"horizon.repro.error": "Паўтор: %s",
|
||||
"horizon.repro.no_recording": "Пакуль няма запісу для экспарту.",
|
||||
"horizon.repro.replay_started": "Паўтор пачаўся: %s",
|
||||
"horizon.pack.addInfo": "Дадайце пакет рэсурсаў з Modrinth",
|
||||
"horizon.pack.addWorking": "Запыт да Modrinth...",
|
||||
"horizon.pack.addNone": "Пакеты рэсурсаў не знойдзены",
|
||||
"horizon.pack.addTitle": "Дадайце пакет рэсурсаў",
|
||||
"horizon.pack.install": "Усталяваць",
|
||||
"horizon.pack.installing": "Ўстаноўка",
|
||||
"horizon.pack.installed": "Усталяваны",
|
||||
"horizon.pack.search": "Пошук",
|
||||
"horizon.pack.searchHint": "Пошук у Modrinth...",
|
||||
"horizon.pack.filters": "Фільтры",
|
||||
"horizon.pack.filter.realistic": "Рэалістычны",
|
||||
"horizon.pack.filter.simplistic": "Спрошчаны",
|
||||
"horizon.pack.filter.vanillaLike": "Ванільны",
|
||||
"horizon.extras.header.cosmetics": "Касметыка",
|
||||
"horizon.extras.cosmetics_mine": "Мая касметыка",
|
||||
"horizon.extras.cosmetics_mine.tooltip": "Схаваны: кожны гулец Horizon бачыць вас без вашай касметыкі, у тым ліку і вас. The same switch as the launcher's Wardrobe.",
|
||||
"horizon.extras.cosmetics_others": "Касметыка іншых гульцоў",
|
||||
"horizon.extras.cosmetics_others.tooltip": "Што носяць іншыя гульцы Horizon: усё, толькі стылі тэгаў з імёнамі або нічога. Hidden, the game never asks what they wear.",
|
||||
"horizon.extras.cosmetics_auras": "Чужыя аўры і шлейфы",
|
||||
"horizon.extras.cosmetics_auras.tooltip": "Auras and trails other players wear. Выключана па змаўчанні.",
|
||||
"horizon.extras.cosmetics.shown": "Паказана",
|
||||
"horizon.extras.cosmetics.hidden": "Схаваны",
|
||||
"horizon.extras.cosmetics.name_tags": "Толькі біркі з імёнамі"
|
||||
}
|
||||
@@ -10,14 +10,11 @@
|
||||
"horizon.options.move_deadzone": "Мъртва зона на движението",
|
||||
"horizon.options.look_deadzone": "Мъртва зона на погледа",
|
||||
"horizon.options.button_glyphs": "Глифове на бутони",
|
||||
"horizon.options.menu_navigation": "Навигация в менюто",
|
||||
"horizon.options.on_screen_keyboard": "Екранна клавиатура",
|
||||
"horizon.options.chat_delay": "Забавяне на чата",
|
||||
"horizon.options.lightbar.health": "здраве",
|
||||
"horizon.options.lightbar.dimension": "Измерение",
|
||||
"horizon.options.glyphs.auto": "Авто",
|
||||
"horizon.options.menu_focus": "Фокус",
|
||||
"horizon.options.menu_pointer": "показалец",
|
||||
"horizon.options.keyboard.auto": "Авто",
|
||||
"horizon.options.keyboard.steam": "Пара",
|
||||
"horizon.options.unavailable": "Тази функция все още не е налична в Horizon.",
|
||||
|
||||
@@ -0,0 +1,481 @@
|
||||
{
|
||||
"horizon.options.controller": "Reoler",
|
||||
"horizon.options.three_d_skin_layers": "Gwiskadoù kroc'hen 3D",
|
||||
"horizon.options.vibration": "Krenadenn",
|
||||
"horizon.options.adaptive_triggers": "Gwaskerioù azasaus",
|
||||
"horizon.options.lightbar": "Barrenn gouloù",
|
||||
"horizon.options.look_sensitivity": "Sensibilitez ar sell",
|
||||
"horizon.options.invert_x": "Distreiñ ar sell X",
|
||||
"horizon.options.invert_y": "Distreiñ ar sell Y",
|
||||
"horizon.options.sneak_button": "Bouton mont kuzh",
|
||||
"horizon.options.move_deadzone": "Takad marv ar fiñval",
|
||||
"horizon.options.look_deadzone": "Takad marv ar sell",
|
||||
"horizon.options.button_glyphs": "Glifoù bouton",
|
||||
"horizon.options.on_screen_keyboard": "Klavier war ar skramm",
|
||||
"horizon.options.chat_delay": "Dale flapañ",
|
||||
"horizon.options.lightbar.health": "Yec'hed",
|
||||
"horizon.options.lightbar.dimension": "Ment",
|
||||
"horizon.options.glyphs.auto": "Emgefreek",
|
||||
"horizon.options.keyboard.auto": "Emgefreek",
|
||||
"horizon.options.unavailable": "N'eo ket hegerz an elfenn-mañ c'hoazh e Horizon.",
|
||||
"horizon.options.search": "Arventennoù klask...",
|
||||
"horizon.pages.mods": "Modoù",
|
||||
"horizon.pages.shader_packs": "Pakadoù skeudennoù",
|
||||
"horizon.pages.shader_options": "Dibarzhioù skeudenniñ",
|
||||
"horizon.pages.controller": "Arventennoù ar merour",
|
||||
"horizon.pages.controller_binds": "Liammañ ar c'hontroller",
|
||||
"horizon.pages.extras": "Horizon Ouzhpennoù",
|
||||
"horizon.pages.settings": "Horizon Arventennoù",
|
||||
"horizon.pages.agent": "Ajañs IA",
|
||||
"horizon.split.leave": "Kuitaat",
|
||||
"horizon.pages.split_settings": "Arventennoù ar skramm rannet",
|
||||
"horizon.pages.split_profiles": "Piv a zo o c'hoari ?",
|
||||
"horizon.pages.split_setup": "Arventennoù ar skramm rannet",
|
||||
"horizon.pages.music": "Sonerezh",
|
||||
"horizon.pages.music.overworld": "Bed dreist",
|
||||
"horizon.pages.music.creative": "Krouiñ",
|
||||
"horizon.pages.music.underwater": "Dindan an dour",
|
||||
"horizon.pages.music.end": "Ar fin",
|
||||
"horizon.pages.music.boss": "Patron",
|
||||
"horizon.pages.music.credits": "Kredoù",
|
||||
"horizon.pages.music.overworld_biomes": "Biomoù ar bed dreist",
|
||||
"horizon.pages.music.nether_biomes": "Biomoù an izelvroioù",
|
||||
"horizon.pages.music.end_biomes": "Biomoù dibenn",
|
||||
"horizon.pages.music.other": "Sonerezh all",
|
||||
"horizon.pages.music.empty": "Roudenn sonerezh ebet : n'eo ket karget sonioù ar c'hoari.",
|
||||
"horizon.pages.music.tooltip": "An hentoù enkorfet, dre stad : c'hoari unan bremañ, pe diweredekaat unan anezho evit ma paouezfe ar c'hoari da zibab anezhañ.",
|
||||
"horizon.pages.settings.tooltip": "arventennoù Horizon e-unan : grafikoù, kontrollerioù, ouzhpennadennoù ha kemmoù.",
|
||||
"horizon.pages.graphics.tooltip": "Grafikoù, simpl : pep arventenn a lavar petra a goust.",
|
||||
"horizon.pages.graphics_advanced.tooltip": "Pep arventenn grafek, Horizon en o zouez, gant ar pezh a goust pep hini.",
|
||||
"horizon.pages.controller.tooltip": "Kontrollerien : o boutonoù, o bizhier, o c'hrennlavar hag o merdeiñ war al lañserioù.",
|
||||
"horizon.pages.extras.tooltip": "Ouzhpennadennoù dibar, holl diweredekaet dre ziouer : chom a ra ar c'hoari vanilha betek ma vo lakaet unan war-sav.",
|
||||
"horizon.pages.agent.tooltip": "Lakait hoc'h ajañs AI da c'hoari : ar c'hliented horizon-ctl ha MCP war an urzhiataer-mañ.",
|
||||
"horizon.pages.split_profiles.tooltip": "Piv a c'hoari : ur profil miret er renkell c'hoari-mañ.",
|
||||
"horizon.pages.split_setup.tooltip": "Ar prenestroù hag ar skrammoù, ha piv a c'hoari pelec'h.",
|
||||
"horizon.pages.shader_packs.tooltip": "Pakadoù skeudennoù eus an teuliad pakadoù skeudennoù : Horizon o-unan hag ar re er stumm skeudennoù/. Unan a red d'an dro.",
|
||||
"horizon.pages.mods.tooltip": "Modoù savet evit Horizon, eus an teuliad horizon-mods. Pep hini a ya en-dro en ur voest-traezh ha chom a ra diweredekaet betek ma vo lakaet war-sav.",
|
||||
"horizon.pages.open.graphics": "Grafikoù...",
|
||||
"horizon.pages.open.graphics_advanced": "Grafikoù araokaet...",
|
||||
"horizon.pages.open.shader_packs": "Pakadoù skeudennoù...",
|
||||
"horizon.pages.open.controller": "Arventennoù ar merour...",
|
||||
"horizon.pages.open.split_setup": "Skramm rannet...",
|
||||
"horizon.pages.open.extras": "Ouzhpenn...",
|
||||
"horizon.pages.open.mods": "Modoù...",
|
||||
"horizon.pages.open.agent": "Ajañs IA...",
|
||||
"horizon.pages.open.horizon_graphics": "Horizon Grafikoù...",
|
||||
"horizon.pages.open.controller_binds": "Stagañ a ra ar reoler...",
|
||||
"horizon.pages.open.horizon_settings": "Horizon Arventennoù...",
|
||||
"horizon.pages.open.music": "Sonerezh...",
|
||||
"horizon.mods.empty": "Mod ebet : lakait restroù .hmod e teuliad horizon-mods",
|
||||
"horizon.mods.stopped": " (Paouezet)",
|
||||
"horizon.mods.not_built": " (N'eo ket bet savet)",
|
||||
"horizon.mods.settings": "Arventennoù",
|
||||
"horizon.mods.in_world": " (lezel ar bed da cheñch)",
|
||||
"horizon.mods.open_folder": "Digeriñ an teuliad mod",
|
||||
"horizon.shader_packs.empty": "Pakad skeudennoù ebet : lakait anezho e teuliad ar pakadoù skeudennoù",
|
||||
"horizon.shader_options.open": "Dibarzhioù skeudenniñ...",
|
||||
"horizon.shader_options.profile": "Profil",
|
||||
"horizon.shader_options.loading": "O lenn dibaboù ar pakad skeudennoù...",
|
||||
"horizon.agent.copy_details": "Eilañ munudoù ar c'hennask",
|
||||
"horizon.multiplayer.join": "Kemer perzh",
|
||||
"horizon.multiplayer.cancel_reconnecting": "Nullañ an adkennaskañ",
|
||||
"horizon.multiplayer.join_friend": "Kemer perzh en ur mignon",
|
||||
"horizon.multiplayer.invite_code": "Kod pediñ",
|
||||
"horizon.multiplayer.relay": "Treuzkas (dibar)",
|
||||
"Preset": "Raktreset",
|
||||
"LOD Distance": "Pellder LOD",
|
||||
"Far Detail": "Munudoù pell",
|
||||
"Cave Culling": "Lazhañ ar c'hevoù",
|
||||
"Entity Culling": "Distruj an entite",
|
||||
"Chunk Updates": "Hizivadennoù tammoù",
|
||||
"Upload Budget": "Budjed pellgargañ",
|
||||
"Sky": "Oabl",
|
||||
"Fog": "Brumenn",
|
||||
"Weather": "Amzer",
|
||||
"Animated Textures": "Teñzorioù bevaat",
|
||||
"Present Mode": "Mod bremañ",
|
||||
"Frame Pacing": "Pazadur ar framm",
|
||||
"Worker Threads": "Neudennoù labourerien",
|
||||
"Resolution Scale": "Skeul an diarunusted",
|
||||
"Anti-aliasing": "Enep-aliañ",
|
||||
"Upscaling": "Kreskiñ",
|
||||
"Paper White": "Gwenn paper",
|
||||
"Peak Brightness": "Sklêrijenn uhelañ",
|
||||
"Black Level": "Live du",
|
||||
"UI Brightness": "Sklêrijenn UI",
|
||||
"Battery Mode": "Mod pilenn",
|
||||
"Graphics API": "API grafikoù",
|
||||
"Translucent Batching": "Lodennadur treuzwelus",
|
||||
"Performance Overlay": "Dreistlakaat ar perzhded",
|
||||
"Full Detail Distance": "Pellder munudoù klok",
|
||||
"On": "War",
|
||||
"Off": "Diweredekaet",
|
||||
"Unlimited": "Didalvoud",
|
||||
"Auto": "Emgefreek",
|
||||
"Custom": "Personelaet",
|
||||
"Performance": "Arvest",
|
||||
"Balanced": "Kempouez",
|
||||
"Quality": "Kalite",
|
||||
"Native": "Natif",
|
||||
"Full": "Leun",
|
||||
"Reduced": "Digresket",
|
||||
"Efficient": "Efedus",
|
||||
"Precise": "Resis",
|
||||
"Auto (VSync)": "Emgefre (VSync)",
|
||||
"Mailbox": "Boest-postel",
|
||||
"Immediate": "Diouzhtu",
|
||||
"FPS and Graph": "FPS ha grafik",
|
||||
"No cost": "Koust ebet",
|
||||
"Low cost": "Koust izel",
|
||||
"Medium cost": "Koust etre",
|
||||
"High cost": "Koust uhel",
|
||||
"Saves time": "Gounit a ra amzer",
|
||||
"Graphics": "Grafikoù",
|
||||
"Done": "Echu",
|
||||
"This feature is not yet available in Horizon.": "N'eo ket hegerz an elfenn-mañ c'hoazh e Horizon.",
|
||||
"Your display or system doesn't offer HDR output.": "Ho skramm pe ho reizhiad ne ginnig ket un disoc'h HDR.",
|
||||
"Turn HDR on to use it.": "Lakait HDR war-sav evit e implijout.",
|
||||
"Your GPU or graphics API doesn't support it.": "N'eo ket skoret gant ho GPU pe ho API grafikoù.",
|
||||
"%s chunks": "%s tammoù",
|
||||
"%s per frame": "%s dre framm",
|
||||
"%s MiB/frame": "%s MiB/framm",
|
||||
"%s KiB/frame": "%s KiB/framm",
|
||||
"Auto (%s)": "Emgefre (%s)",
|
||||
"Full-detail terrain range. LOD Distance can extend local worlds farther.": "Rannvro an douaroù leun a vunudoù. LOD Ar pellder a c'hell astenn ar bedoù lec'hel pelloc'h.",
|
||||
"Coarse distant terrain in local worlds. Integrated GPUs stop at 128 chunks.": "Douaroù pell gros e bedoù lec'hel. Paouez a ra ar GPUoù kevredet da 128 tamm.",
|
||||
"Reduced draws far terrain coarser: faster on this integrated GPU.": "Digreskiñ a ra an douaroù kalz grosoc'h : buanoc'h war ar GPU kevredet-mañ.",
|
||||
"Reduced draws far terrain coarser, for GPUs it slows down.": "Ar reduset a denn an douaroù kalz grosoc'h, evit ar GPUoù e vez gorrekaet.",
|
||||
"Field of view. Wider shows more terrain at once.": "Tachenn gwel. Ledanoc'h a ziskouez muioc'h a zouaroù war un dro.",
|
||||
"Caps frames per second; a cap saves power and heat.": "Bep frammoù dre eilenn; ur c'hasketenn a espern energiezh ha tommder.",
|
||||
"Waits for the display's refresh: no tearing, a little latency.": "Gortoz a ra freskaat ar skramm : tamm torr ebet, un tamm dale.",
|
||||
"Size of menus and the HUD.": "Ment ar mennozhioù hag an HUD.",
|
||||
"Sets the options below together. Changing one makes it Custom.": "Lakaat a ra an dibarzhioù amañ dindan asambles. Cheñch unan a ra anezhañ Personelaet.",
|
||||
"Lava, fire and sunlight shine brighter than white. Needs an HDR display.": "Lava, tan ha gouloù an heol a lugern muioc'h eget ar gwenn. Ezhomm zo eus ur skramm HDR.",
|
||||
"Your display's darkest black. 0 for OLED; LCDs glow a little.": "Du teñvalañ eo ho skramm. 0 evit OLED; LCDoù a lugern un tamm.",
|
||||
"How bright highlights get. Auto: the peak your system reports.": "Pegen skedus e teu ar sklêrijennoù. Emgefre : ar pik a vez embannet gant ho reizhiad.",
|
||||
"How bright white paper and menus look. Auto: your desktop's white.": "Pegen skedus e seblant ar paper gwenn hag ar mennozhioù. Emgefre : gwenn eo ho burev.",
|
||||
"How bright the HUD and menus are, against paper white.": "Pegen skedus eo an HUD hag ar mennozhioù, a-enep gwenn ar paper.",
|
||||
"How far mobs, crops and machines keep working. CPU time.": "Pegen pell e kendalc'h ar mobs, ar c'hoadoù hag ar mekanikoù da labourat. Amzer ar CPU.",
|
||||
"How far away mobs and items are drawn, as a share of normal.": "Pegen pell e vez tennet ar mobs hag an traoù, evel ul lodenn eus ar pezh a vez graet normal.",
|
||||
"Skips terrain hidden behind closed sections. Off costs a lot.": "Tremen a ra an douaroù kuzhet a-dreñv rannoù serr. Koustañ a ra kalz.",
|
||||
"Hides entities behind opaque blocks.": "Kuzhat a ra an elfennoù a-dreñv bloc'hoù dister.",
|
||||
"No entity occlusion culling.": "N'eus ket a zistruj entite.",
|
||||
"CPU occlusion test runs this frame.": "Test stankañ ar CPU a gas ar framm-mañ da benn.",
|
||||
"Occlusion checks run on a worker thread.": "Ar gwirioù stankañ a vez kaset da benn war un neudenn labourer.",
|
||||
"Meshed sections uploaded per frame. Lower is smoother while loading.": "Rannoù rouedek pellgarget dre framm. Eeunoc'h eo an izelañ e-pad ar c'hargañ.",
|
||||
"Soft shadows in corners. Costs chunk building time only.": "Skeudoù dous er c'hornioù. Koustañ a ra amzer sevel a-stroll hepken.",
|
||||
"Smaller copies of block textures for distant terrain: less shimmer.": "Skouerennoù bihanoc'h eus teñzorioù bloc'hoù evit an tachennoù pell : nebeutoc'h a sked.",
|
||||
"Blends grass and water colours across biomes when building chunks.": "Meskañ a ra livioù ar geot hag an dour dre ar biomoù pa vez savet tammoù.",
|
||||
"Cloud layer: off, flat (fast) or 3D (fancy).": "Treuzfollenn ar c'hoad : diweredekaet, plaen (buan) pe 3D (fentus).",
|
||||
"How far clouds reach, in chunks.": "Pegen pell e tizh ar c'houmoul, e tammoù.",
|
||||
"Draws the sky, sun, moon and stars.": "Tresañ a ra an oabl, an heol, al loar hag ar stered.",
|
||||
"Distance fog. Off shows the edge of the loaded world.": "Brumenn pellder. Diweredekaat a ziskouez ribl ar bed karget.",
|
||||
"Draws rain and snow.": "Tennañ a ra glav hag erc'h.",
|
||||
"How far rain and snow fall around you.": "Pegen pell e kouezh ar glav hag an erc'h en-dro deoc'h.",
|
||||
"How many particles effects spawn.": "Peseurt efedoù rannigoù a vez ganet.",
|
||||
"Round shadows under mobs and items.": "Skeudennoù ront dindan mobs hag elfennoù.",
|
||||
"Leaves with see-through gaps. Off draws them solid.": "Delioù gant toulloù gwelus. Off a denn anezho start.",
|
||||
"Sorts water and glass more exactly behind each other.": "Renkañ a ra an dour hag ar gwer an eil a-dreñv egile.",
|
||||
"Which chunk rebuilds wait for the frame: none, nearby or yours.": "Peseurt rann a adsevel a c'hortoz ar framm : hini ebet, e-kichen pe ho hini.",
|
||||
"Animates water, lava, fire and other moving textures.": "Bevaat a ra an dour, al lava, an tan hag an danvezioù fiñvus all.",
|
||||
"World pixels per screen pixel. Below 100% is faster on the GPU.": "Pikseloù bed dre piksel skramm. Buanoc'h eo dindan 100% war ar GPU.",
|
||||
"Smooths jagged edges. FXAA: softer. TAA: smoothest, moving things may trail.": "Eeunaat a ra ar c'hornioù ruz. FXAA: dousoc'h. TAA: an traoù eeunañ, o fiñval a c'hell heuliañ.",
|
||||
"Renders the world smaller and rebuilds it with TAA. Faster, softer.": "Bihanaat a ra ar bed hag adsevel anezhañ gant TAA. Buanoc'h, dousoc'h.",
|
||||
"HDR output on an HDR display: lava, fire and sunlight shine brighter.": "Disoc'h HDR war ur skramm HDR : lava, tan ha gouloù an heol a lugern muioc'h.",
|
||||
"How frames reach the screen while VSync is off.": "Penaos e tistro ar frammoù war ar skramm pa vez diweredekaet VSync.",
|
||||
"Efficient sleeps until the next frame; Precise spins, like vanilla.": "Kousket a ra efedus betek ar framm da heul; Troioù resis, evel ar vanilha.",
|
||||
"Fills the screen (borderless).": "Leuniañ ar skramm (hep bevennoù).",
|
||||
"Brightens dark places.": "Sklaeraat a ra al lec'hioù teñval.",
|
||||
"Lowers the frame rate when minimised, or idle too.": "Digreskiñ a ra ar feur framm pa vez bihanaet, pe pa vez didalvoud ivez.",
|
||||
"Sways the view while walking.": "Heñchañ a ra ar gwel e-pad ma kerzher.",
|
||||
"Fades newly loaded chunks in.": "Diverkañ a ra an tammoù nevez karget.",
|
||||
"Darkens the screen's edges.": "Teñvalaat a ra ribloù ar skramm.",
|
||||
"Shows when the world saves.": "Diskouez a ra pa savete ar bed.",
|
||||
"Shows attack cooldown.": "Diskouez a ra an amzer yenaat evit an taolioù.",
|
||||
"60 FPS cap (30 in menus or unfocused), half the workers: less power.": "60 FPS (30 er mennozhioù pe diskoulmet), an hanter eus al labourerien : nebeutoc'h a c'halloud.",
|
||||
"Threads that generate, light and mesh chunks. Next start.": "Neudennoù a grou, a luc'h hag a ro troc'hadoù. Kregiñ war-lerc'h.",
|
||||
"Vulkan, then DirectX 12 (Windows) or OpenGL (Linux) where it fails. Next start.": "Vulkan, neuze DirectX 12 (Windows) pe OpenGL (Linux) ma c'hwit. Kregiñ war-lerc'h.",
|
||||
"Water and glass in one buffer: fewer draw calls, a bit more VRAM. Next start.": "Dour ha gwer en ur buffer : nebeutoc'h a c'halvoù tennañ, un tamm muioc'h a VRAM. Kregiñ war-lerc'h.",
|
||||
"Mesh data sent to the GPU per frame. Lower is smoother while loading.": "Roadennoù rouedad kaset d'ar GPU dre framm. Eeunoc'h eo an izelañ e-pad ar c'hargañ.",
|
||||
"Frame rate and frame times over the game, with a graph.": "Feur ar framm hag an amzer framm e-pad ar c'hoari, gant ur grafik.",
|
||||
"horizon.multiplayer.finding_friend": "O kavout bed ho mignon...",
|
||||
"horizon.multiplayer.not_signed_in": "E mod enlinenn emañ an dafariad-mañ. En em lugañ gant ho kont Microsoft el lañser Horizon evit mont e-barzh.",
|
||||
"horizon.multiplayer.invalid_address": "Chomlec'h servijer direizh : %s",
|
||||
"horizon.multiplayer.connected_friend_direct": "Kevreet war-eeun ouzh ho mignon...",
|
||||
"horizon.multiplayer.connected_friend_relay": "Kevreet ouzh ho mignon dre ar c'heflusker...",
|
||||
"General": "Hollek",
|
||||
"Advanced": "Araokaet",
|
||||
"Undo": "Dizober",
|
||||
"Search options": "Dibarzhioù klask",
|
||||
"Shortcut": "Berradennoù",
|
||||
"Distance": "Pellder",
|
||||
"Display": "Diskouez",
|
||||
"Interface": "Etrefas",
|
||||
"Sky and weather": "Oabl hag amzer",
|
||||
"Lighting and entities": "Gouloù hag ensavadurioù",
|
||||
"Textures": "Teñzorioù",
|
||||
"Image": "Skeudenn",
|
||||
"Chunk loading": "Kargañ tammoù",
|
||||
"Culling": "Lazhañ",
|
||||
"Power": "Galloud",
|
||||
"Frames": "Frammoù",
|
||||
"Overlay": "Dreistlakaat",
|
||||
"Output": "Disoc'h",
|
||||
"Brightness": "Sklêrijenn",
|
||||
"How far you see, the window and the HUD.": "Pegen pell e weler, ar prenestr hag an HUD.",
|
||||
"The sky and weather, lighting, textures and the image.": "An oabl hag an amzer, ar gouloù, an teñzorioù hag ar skeudenn.",
|
||||
"Chunk loading, culling and power use.": "Kargañ troc'hadoù, distrujañ hag implij ar galloud.",
|
||||
"How frames reach the screen, and the performance overlay.": "Penaos e tistro ar frammoù d'ar skramm, hag an dreuzfollenn perzhded.",
|
||||
"Brighter-than-white output on an HDR display.": "Disoc'h sklaeroc'h eget gwenn war ur skramm HDR.",
|
||||
"Results for \"%s\"": "Disoc'hoù evit \"%s\"",
|
||||
"No settings match.": "Arventennoù ebet a glot.",
|
||||
"horizon.title.not_affiliated": "N'eo ket stag ouzh Mojang pe Microsoft",
|
||||
"horizon.extras.header.lighting": "Gouloù",
|
||||
"horizon.extras.header.third_person": "Trede gour",
|
||||
"horizon.extras.header.particles": "Rannigoù",
|
||||
"horizon.extras.header.inventory": "Enrolladenn",
|
||||
"horizon.extras.header.chat": "Flapañ",
|
||||
"horizon.extras.header.multiplayer": "Liesc'hoarier",
|
||||
"horizon.extras.header.sound": "Son",
|
||||
"horizon.extras.header.menus": "Mennozhioù",
|
||||
"horizon.extras.dynamic_lights": "Gouloù dinamek",
|
||||
"horizon.extras.own_name_tag": "Tikedenn anv e-unan",
|
||||
"horizon.extras.hide_block_particles": "Kuzhat rannigoù bloc'h-torr",
|
||||
"horizon.extras.auto_reconnect": "Adkevreañ emgefre",
|
||||
"horizon.extras.ui_sound_reserve": "Mirout ar chadennoù evit sonioù an UI",
|
||||
"horizon.extras.music_page": "Pajenn sonerezh",
|
||||
"horizon.extras.mouse_tweaks": "Reolennoù kemmañ al logodenn",
|
||||
"horizon.extras.mouse_tweaks_wheel": "Ar rod riklañ a zilec'h elfennoù",
|
||||
"horizon.extras.sort": "Boutonoù renkañ",
|
||||
"horizon.extras.sort_key": "Alc'hwez renkañ",
|
||||
"horizon.extras.no_ai": "AI ebet",
|
||||
"horizon.extras.agent_control": "Kontroll an ajañs",
|
||||
"horizon.extras.discord_presence": "Discord Bezañs pinvidik",
|
||||
"horizon.extras.splitscreen": "Skramm rannet",
|
||||
"horizon.extras.chat_animation": "Flapañ eeun",
|
||||
"horizon.extras.chat_indicator": "Merk kemennadenn",
|
||||
"horizon.extras.wheel_cycles_settings": "Kemmañ a ra arventennoù ar rouedad riklañ",
|
||||
"horizon.extras.pack_browser": "Merdeer pakadoù arc'hwelioù",
|
||||
"horizon.extras.fullbright.tooltip": "Diskouez bloc'hoù hag elfennoù e-pad ar gouloù leun, zoken e lec'hioù teñval.",
|
||||
"horizon.extras.dynamic_lights.tooltip": "Torchoù ha fontoù gouloù all dalc'het, taolet pe en tan a sklêrijenn ar bloc'hoù tro-dro dezho.",
|
||||
"horizon.extras.own_name_tag.tooltip": "Diskouez a ra hoc'h anv a-us d'ho penn en trede gour, evel ma vez gwelet gant ar c'hoarierien all. Kuzhet pa vez kuzhet anvioù ho skipailh gant an dafariad pe pa vezit diwelus.",
|
||||
"horizon.extras.hide_block_particles.tooltip": "Kuzhat a ra ar rannigoù lastez a darzh diwar ur bloc'h torret hag a zismantr diwar an hini a vez tennet ganeoc'h. Chom a ra rannigoù all.",
|
||||
"horizon.extras.auto_reconnect.tooltip": "Adkemer perzh en ur servijer goude ur c'hennask kollet pe un adloc'hañ, biskoazh goude ur c'hrogad pe ur bann.",
|
||||
"horizon.extras.ui_sound_reserve.tooltip": "Ar sonioù er bed a lez 16 eus ar 247 chadenn son digoust, setu ne c'hell ket ur bern anezho (ur splujadenn vras) sioulaat ar c'hlikoù war al lañser.",
|
||||
"horizon.extras.music_page.tooltip": "Music & Sounds a gav ur bajenn Sonerezh... : seniñ un ton enkorfet bremañ, pe diweredekaat unan evit ma paouezfe ar c'hoari da zibab anezhañ. Ne cheñch netra betek ma vo lazhet un hent.",
|
||||
"horizon.extras.mouse_tweaks.tooltip": "An riklañ a-zehou a laka unan dre lec'h, an riklañ a-gleiz a zastum an elfenn dalc'het, an riklañ Shift + an riklañ a-gleiz a zilec'h pep rann.",
|
||||
"horizon.extras.mouse_tweaks_wheel.tooltip": "Down a gas un elfenn eus ar rann d'an tu all, up a zegas unan en-dro.",
|
||||
"horizon.extras.sort.tooltip": "Urzhiañ a ra an enrolladennoù, ar c'hofoù, ar barilhoù, ar c'hofoù ender hag ar boestoù shulker en urzh ivinelloù krouiñ, o kendeuziñ ar bernoù.",
|
||||
"horizon.extras.sort_key.tooltip": "Urzhiañ a ra al lodenn dindan ar merdeer. Klikañ, ha pouezañ war un alc'hwez ; Tec'hout a zistag anezhañ.",
|
||||
"horizon.extras.no_ai.tooltip": "Kuzhat ha diweredekaat pep elfenn AI : kontroll an ajañs, horizon-ctl hag ar servijerioù MCP. Alc'hwez al lañser ivez.",
|
||||
"horizon.extras.agent_control.tooltip": "Hoc'h ajañs IA a c'hall c'hoari ar c'hoari-mañ dre horizon-ctl pe dre ur c'hlient MCP, war an urzhiataer-mañ hepken.",
|
||||
"horizon.extras.discord_presence.tooltip": "Diskouez a ra C'hoari Horizon war ho profil Discord e-keit ma vez Discord o vont en-dro : mennozhioù, c'hoarier unvan pe liesc'hoarier, ar vent hag an amzer c'hoariet. Biskoazh anv ur bed pe chomlec'h ur servijer.",
|
||||
"Calibrate...": "Kalibrañ...",
|
||||
"Calibrate Anyway...": "Kalibrañ koulskoude...",
|
||||
"Use Automatic Setup": "Implijout arventennoù emgefre",
|
||||
"Shortcut: %s": "Berradennoù : %s",
|
||||
"Next": "Da heul",
|
||||
"HDR Calibration %s/%s: %s": "Kalibradur HDR %s/%s : %s",
|
||||
"Sets the three below full screen, one test picture at a time.": "Lakaat a ra an tri skramm leun a-is, ur skeudenn amprouiñ bep tro.",
|
||||
"A key that opens this screen from the game. Not bound at first.": "Un alc'hwez a zigor ar skramm-mañ eus ar c'hoari. N'eo ket stag da gentañ.",
|
||||
"Your display didn't say how bright it gets: calibrate to set it up.": "N'eo ket bet embannet gant ho skramm pegen sklaer e teu da vezañ : kalibret evit e lakaat war-sav.",
|
||||
"Already set up for your display. Only calibrate if HDR looks wrong.": "Kefluniet dija evit ho skramm. Kalibret nemet ma seblant HDR bezañ fazius.",
|
||||
"Puts Peak Brightness and Paper White back to your display's setup.": "Lakaat a ra ar sked uhelañ hag ar gwenn paper en-dro e kefluniadur ho skramm.",
|
||||
"Set up for your display. Leave on Auto unless it looks wrong.": "Kefluniañ evit ho skramm. Lezel war Auto nemet pa seblant fall.",
|
||||
"Lower it until the logo just disappears into the black.": "Izelaat anezhañ betek ma vo kollet al logo en du.",
|
||||
"Raise it until the logo just disappears into the bright square.": "Sevel anezhañ betek ma vo kollet al logo er c'harrez skedus.",
|
||||
"Make the card a white that's comfortable to look at for a long time, in the light you play in.": "Lakaat ar gartenn da vezañ gwenn a vo aes da sellet outi e-pad pell, er gouloù ma c'hoarier.",
|
||||
"horizon.splitscreen.profiles.forget": "Ankounac'haat",
|
||||
"horizon.splitscreen.profiles.create": "Krouiñ",
|
||||
"horizon.splitscreen.profiles.you": " - c'hwi",
|
||||
"horizon.splitscreen.profiles.forget_named": "Ankouaat %s",
|
||||
"horizon.splitscreen.profiles.previous": "Kent",
|
||||
"horizon.splitscreen.profiles.next": "Da heul",
|
||||
"horizon.splitscreen.profiles.new_button": "Profil nevez...",
|
||||
"horizon.splitscreen.profiles.forget_title": "Ankounac'haat ho profil ?",
|
||||
"horizon.splitscreen.profiles.forget_leaves": "Kuitaat a ra roll an ensavadur-mañ.",
|
||||
"horizon.splitscreen.profiles.forget_kept": "Miret e vez an araokadennoù hag an arventennoù er bed.",
|
||||
"horizon.splitscreen.profiles.new_title": "Profil nevez",
|
||||
"horizon.splitscreen.profiles.name_hint": "Anv (3 da 16 lizherenn, sifroù, _)",
|
||||
"horizon.splitscreen.profiles.switch_title": "Cheñch profil",
|
||||
"horizon.splitscreen.profiles.offline_note": "Ar profiloù ezlinenn a ya d'ober an ensavadur-mañ",
|
||||
"horizon.splitscreen.profiles.move": "Dilec'hiañ el lec'h ma c'hoarier",
|
||||
"horizon.splitscreen.profiles.move_place": "Dilec'hiañ el lec'h ma c'hoarier : %s",
|
||||
"horizon.friends.title": "C'hoari gant mignoned",
|
||||
"horizon.friends.hint": "Pegañ a ra ar vignoned ar c'hod goude bouton Mignoned ar skramm titl, e Kevreadur war-eeun, pe war bajenn C'hoari al lañser.",
|
||||
"horizon.friends.copied": "Eilet",
|
||||
"horizon.friends.copy_code": "Eilañ ar c'hod",
|
||||
"horizon.friends.stop_sharing": "Paouez da rannañ",
|
||||
"horizon.friends.none_yet": "Mignon ebet amañ c'hoazh.",
|
||||
"horizon.friends.here_now": "Setu bremañ : %s",
|
||||
"horizon.friends.share_intro": "Rannañ ar bed-mañ a-dreñv ur c'hod pediñ : digeriñ a ra d'ar LAN, ha mignoned war internet a gemer perzh gant ar c'hod. N'eus servijer ebet ac'hanomp e-barzh.",
|
||||
"horizon.friends.start_sharing": "Kregiñ da rannañ",
|
||||
"horizon.friends.troubleshooting": "Diskoulmañ kudennoù...",
|
||||
"horizon.friends.stopped": "Paouezet da rannañ ar c'hod pediñ.",
|
||||
"horizon.friends.short_code_changed": "Unan bennak a gendalc'has da glask ur c'hod berr fazius, setu m'eo cheñchet.",
|
||||
"horizon.friends.wrong_code": "Unan bennak en deus klasket ur c'hod fall.",
|
||||
"horizon.friends.code_ready": "Prest eo ho kod pediñ : Menü ar c'hoari, C'hoari gant mignoned. Eilañ anezhañ ha kas anezhañ d'ho mignoned.",
|
||||
"horizon.friends.share_failed": "N'hall ket rannañ ar bed : %s",
|
||||
"horizon.friends.finding_route": "Kavout penaos e c'hall mignoned tizhout ac'hanoc'h...",
|
||||
"horizon.osk.shift": "Dilec'hiañ",
|
||||
"horizon.osk.space": "Egor",
|
||||
"horizon.osk.delete": "Dilemel",
|
||||
"horizon.osk.type": "Seurt",
|
||||
"horizon.osk.symbols": "Arouezioù",
|
||||
"horizon.osk.close": "Serriñ",
|
||||
"horizon.extras.chat_animation.tooltip": "Ur linenn flapañ nevez a zeu eus an tu kleiz e-keit ma vez o vont da get, e-lec'h dont war wel a-bezh.",
|
||||
"horizon.extras.chat_indicator.tooltip": "Ar varrenn livet a-gleiz d'ul linenn flapañ.",
|
||||
"horizon.extras.wheel_cycles_settings.tooltip": "Ar rod riklañ war ur bouton en arventennoù a gemm e dalvoudegezh, evel e vanilha. Diweredekaet, ne ra ar rod nemet riklañ ar roll.",
|
||||
"horizon.extras.pack_browser.tooltip": "Dibab pakadoù arc'hwelioù a resev ur bouton Ouzhpennañ a glask Modrinth hag a staliañ ur pakad en ho teuliad pakadoù. Diweredekaet, ne vez ket darempredet ar c'hoari gant Modrinth.",
|
||||
"horizon.extras.splitscreen.tooltip": "En ur bed e c'hall ur c'hontroller all mont e-barzh evel c'hoarier nevez : pouezit war A pa c'houlenn, ha dibabit ur profil ha pelec'h c'hoari.",
|
||||
"horizon.splitscreen.setup.monitor": "Heuliañ %s",
|
||||
"horizon.splitscreen.setup.monitor_unknown": "ur skramm",
|
||||
"horizon.splitscreen.setup.window": "Prenestr %s",
|
||||
"horizon.splitscreen.setup.new_window": "Prenestr nevez",
|
||||
"horizon.splitscreen.setup.fill_monitor": "Leuniañ %s",
|
||||
"horizon.splitscreen.setup.done": "Echu",
|
||||
"horizon.splitscreen.setup.on": "War",
|
||||
"horizon.splitscreen.setup.off": "Diweredekaet",
|
||||
"horizon.splitscreen.setup.player": "C'hoarier %s",
|
||||
"horizon.splitscreen.setup.revert": "Distreiñ",
|
||||
"horizon.splitscreen.setup.apply": "Goulenn",
|
||||
"horizon.splitscreen.setup.warning.empty_main": "Den ne c'hoari e Prenestr 1 : kuzhat a ra",
|
||||
"horizon.splitscreen.setup.warning.empty_close": "Den ne c'hoari e Prenestr %s : serriñ a ra war Apply",
|
||||
"horizon.splitscreen.setup.warning.empty_new": "Den ne c'hoari e Prenestr %s : ne vo ket digoret",
|
||||
"horizon.splitscreen.setup.warning.on_main": "Prenestr %s a leun skramm ar prenestr 1 : e c'hoarierien a c'hoari e prenestr 1",
|
||||
"horizon.splitscreen.setup.warning.unplugged": "N'eo ket kevreet skramm ar Prenestr %s : c'hoari a ra e c'hoarierien e Prenestr 1",
|
||||
"horizon.splitscreen.setup.status.off": "Diweredekaet eo ar skramm rannet.",
|
||||
"horizon.splitscreen.setup.status.enable_hint": "Lakait anezhañ war enaou, ha pouezit war ur bouton war ur c'hontroller all en ur bed.",
|
||||
"horizon.splitscreen.setup.status.join_hint": "Pouezit war A evit mont e-barzh ha dibab ur profil.",
|
||||
"horizon.splitscreen.setup.status.idle": "Skramm rannet didalvoud",
|
||||
"horizon.splitscreen.setup.status.alone": "C'hoarier lec'hel all ebet.",
|
||||
"horizon.splitscreen.setup.status.solo_controls": "Ar c'hontrolloù solo hag an evezhiadennoù kontroller n'int ket cheñchet.",
|
||||
"horizon.splitscreen.setup.window_empty": "Prenestr %s: goullo",
|
||||
"horizon.splitscreen.setup.note.select": "Klikit war ur c'hoarier, pe riklañ anezhañ betek ur prenestr pe ur skramm.",
|
||||
"horizon.splitscreen.setup.note.apply": "Arverañ evit c'hoari evel-se, Distreiñ evit distreiñ.",
|
||||
"horizon.splitscreen.setup.note.place": "Pelec'h e tlefe %s c'hoari ?",
|
||||
"horizon.splitscreen.setup.this_player": "ar c'hoarier-mañ",
|
||||
"horizon.splitscreen.setup.switch_disabled": "Lazhañ a ra ar skramm rannet ur wech ma'z a ar re all kuit (o lañser paouez).",
|
||||
"horizon.splitscreen.setup.window_place": "Prenestr %s (%s eus %s)",
|
||||
"horizon.splitscreen.setup.names": "Anvioù",
|
||||
"horizon.splitscreen.setup.identify": "Anavezout",
|
||||
"horizon.splitscreen.setup.layout.two": "2 rannañ : %s",
|
||||
"horizon.splitscreen.setup.layout.three": "3 rannañ : %s",
|
||||
"horizon.splitscreen.setup.layout.two.0": "Emgefreek",
|
||||
"horizon.splitscreen.setup.layout.two.1": "Kichen-ha-kichen",
|
||||
"horizon.splitscreen.setup.layout.two.2": "Krec'h ha traoñ",
|
||||
"horizon.splitscreen.setup.layout.three.0": "Unan ledan war-c'horre",
|
||||
"horizon.splitscreen.setup.layout.three.1": "Unan uhel a-gleiz",
|
||||
"horizon.splitscreen.setup.layout.three.2": "Kichen-ha-kichen",
|
||||
"horizon.splitscreen.setup.help.player": "Klikañ pe riklañ %s evit o dilec'hiañ.",
|
||||
"horizon.splitscreen.setup.help.layout_auto": "%s (kichen-ha-kichen pa vez ledan ar prenestr). Pouezit evit cheñch.",
|
||||
"horizon.splitscreen.setup.help.layout": "%s. Pouezit evit cheñch.",
|
||||
"horizon.splitscreen.setup.help.switch": "Skramm rannet evit an urzhiataer-mañ, war pe get.",
|
||||
"horizon.splitscreen.setup.help.identify": "Gwel pep c'hoarier a ziskouez e peseurt prenestr emañ.",
|
||||
"horizon.splitscreen.setup.help.names": "Anv pep c'hoarier e korn o gwel.",
|
||||
"horizon.splitscreen.setup.help.revert": "Dilemel ar c'hemmoù n'int ket bet arveret c'hoazh.",
|
||||
"horizon.splitscreen.setup.help.apply": "C'hoari evel ma tiskouez ar gartenn.",
|
||||
"horizon.splitscreen.setup.help.unchanged": "N'eus netra cheñchet c'hoazh.",
|
||||
"horizon.splitscreen.setup.give_up_pad": "Pad dilezel",
|
||||
"horizon.splitscreen.prompt.controller_connected": "Reoler kevreet",
|
||||
"horizon.splitscreen.prompt.controller_disconnected": "Diskennet eo ar c'hontroller",
|
||||
"horizon.splitscreen.prompt.controller_disconnected.hint": "Adkevreit anezhañ, pe pouezit war ur bouton war unan all",
|
||||
"horizon.splitscreen.prompt.join.one": "%s a fell dezhañ mont e-barzh",
|
||||
"horizon.splitscreen.prompt.join.many": "%s kontrollerien a fell dezho kemer perzh",
|
||||
"horizon.splitscreen.prompt.join.yes": "Kemer perzh",
|
||||
"horizon.splitscreen.prompt.join.as_p1": "C'hoari evel P1",
|
||||
"horizon.splitscreen.prompt.join.no": "Nann",
|
||||
"horizon.splitscreen.prompt.lost": "%s: distaget eo ar c'hontroller",
|
||||
"horizon.splitscreen.prompt.lost.use_another": "Implijout unan all",
|
||||
"horizon.splitscreen.prompt.lost.leave": "Kuitaat",
|
||||
"horizon.splitscreen.setup.help.give_up_pad": "Paouez a ra ho kontroller da gas ac'hanoc'h ha kinniget e vez deoc'h mont e-barzh (A).",
|
||||
"horizon.splitscreen.setup.note.held_at": "%s da %s: A a laka anezhañ da gouezhañ amañ, B a laka anezhañ en-dro.",
|
||||
"horizon.splitscreen.setup.note.held": "%s dastumet : dibaboù kleiz/dehou e-lec'h ma kouezh A, B a laka anezhañ en-dro.",
|
||||
"horizon.splitscreen.online_only": "E mod enlinenn emañ ar servijer-mañ : n'hall ket ar profiloù ezlinenn mont e-barzh, pep c'hoarier en deus ezhomm eus e gont Minecraft.",
|
||||
"horizon.splitscreen.own_account": "Ezhomm en deus ar servijer-mañ eus ur gont Minecraft evit pep c'hoarier",
|
||||
"horizon.splitscreen.local_only": "Ar c'hoarierien all ne c'hallont mont e-barzh ar servijer-mañ nemet gant o c'hont Minecraft o-unan : ar profiloù ezlinenn a c'hoari en ho bed, war LAN pe war ur servijer war ho rouedad lec'hel.",
|
||||
"Hides models behind opaque blocks. Async checks off-thread; entities tick.": "Kuzhat a ra ar patromoù a-dreñv bloc'hoù dister. Gwiriañ a ra an async e-maez an neudennad; tik an entiteoù.",
|
||||
"Block Entities": "Entiteoù stankañ",
|
||||
"Shulker Boxes": "Boestoù Shulker",
|
||||
"Reuses settled boxes; lid movement stays animated.": "Adimplij a ra ar voestoù staliet; fiñv ar golo a chom bev.",
|
||||
"Signs": "Sinoù",
|
||||
"Reuses sign text until text, light, or font changes.": "Adlakaat a ra testenn ar sin betek ma cheñcho an destenn, ar gouloù pe ar font.",
|
||||
"Decorated Pots": "Podoù kinklet",
|
||||
"Reuses still pots; break wobble and sherd changes redraw.": "Adimplij a ra podoù c'hoazh; terriñ ar c'hrennlazh hag ar c'hemmoù strinkañ adtresañ.",
|
||||
"Bells": "Klochennoù",
|
||||
"Reuses still bells; ringing stays animated.": "Adimplij a ra kloc'hioù c'hoazh; chom a ra bevaat ar sonerezh.",
|
||||
"Chests": "Kofoù",
|
||||
"Reuses closed chests; moving lids stay animated.": "Adimplij ar c'houfr serr; ar goloioù o fiñval a chom bev.",
|
||||
"Banners": "Bannieloù",
|
||||
"Reuses poles; flags and pattern layers still update.": "Adimplij ar palioù; hizivaet c'hoazh ar bannieloù hag ar gwiskadoù patromoù.",
|
||||
"Copper Golem Statues": "Delwennoù golem kouevr",
|
||||
"Reuses statue geometry until its block state changes.": "Adlakaat a ra geometriezh an delwenn betek ma cheñcho he stad bloc'h.",
|
||||
"Leaf Culling": "Lazhañ delioù",
|
||||
"Every leaf face. Vanilla's fancy leaves.": "Pep delienn dremm. Delioù fentus ar vanilha.",
|
||||
"Distant Plant Dither": "Tremen a ra ar plant pell",
|
||||
"Keeps fine plants in high-res packs from fading far away.": "Mirout a ra ar plant fin e pakadoù uhel o resolution da vont da get pell.",
|
||||
"Screenshot Quality": "Kalite ar skramm",
|
||||
"F2 screenshots at this many times the game's resolution. Higher takes longer.": "Skeudennoù skramm F2 gant kement-se meur a wech diarunusted ar c'hoari. Uheloc'h a bad hiroc'h.",
|
||||
"Frame Generation": "Krouiñ frammoù",
|
||||
"Shows a made-up frame between each two real ones: smoother, a little more lag.": "Diskouez a ra ur framm savet etre pep daou hini gwirion : eeunoc'h, un tamm muioc'h a zilez.",
|
||||
"Shadow Cache": "Grubuilh skeud",
|
||||
"Reuses the pack shadow map when sun, view and world match. Off by default.": "Adimplij ar gartenn skeud pakad pa glot an heol, ar gwel hag ar bed. Diweredekaet dre ziouer.",
|
||||
"Find BlueMap": "Kavout BlueMap",
|
||||
"On servers, finds their BlueMap web map for far terrain. Next join.": "War ar servijerioù e kaver o gartenn web BlueMap evit an tachennoù pell. Kemer perzh da heul.",
|
||||
"BlueMap Radius": "Radius ar gartenn glas",
|
||||
"How far around you BlueMap tiles are downloaded. Next join.": "Pegen pell tro-dro deoc'h e vez pellgarget teulioù BlueMap. Kemer perzh da heul.",
|
||||
"Synchronous": "Sinkron",
|
||||
"Asynchronous": "Azinkron",
|
||||
"Solid Aggressive": "Tagus kreñv",
|
||||
"Hollow": "Toull",
|
||||
"Leaves fully inside a canopy draw solid: fewer see-through layers.": "Delioù penn-da-benn e-barzh ur c'hoad a denn solut : nebeutoc'h a gwiskadoù treuzwelus.",
|
||||
"Leaves with one open side draw solid too: faster, chunkier edges.": "Ar delioù gant un tu digor a denn ivez : bordoù buanoc'h ha stankoc'h.",
|
||||
"Drops faces between leaves: faster, but gaps look through.": "Lakaat a ra fazioù etre ar delioù : buanoc'h, met toulloù a sell drezo.",
|
||||
"Hotbar: Previous Slot": "Barrenn-dre-lien : Lec'h a-raok",
|
||||
"Hotbar: Next Slot": "Barrenn-dre-lien : Lec'h war-lerc'h",
|
||||
"horizon.agent.connected.one": "Kevreet : 1 kevreadenn ajañs",
|
||||
"horizon.agent.connected.many": "Kevreet : %s kevreadennoù an ajañs",
|
||||
"horizon.agent.connected.one_ago": "Kevreet : 1 kevreadenn ajañs, ur gemennadenn ziwezhañ %s s zo",
|
||||
"horizon.agent.connected.many_ago": "Kevreet : %s kevreadennoù an ajañs, ar gemennadenn ziwezhañ %s s zo",
|
||||
"horizon.agent.waiting": "O c'hortoz un ajañs.",
|
||||
"horizon.agent.off": "Diweredekaet : n'hall ket an ajañsoù tizhout ar c'hoari-mañ.",
|
||||
"horizon.agent.session_opened": "Digoret evit ar prantad-mañ gant ar programm en deus kroget ar c'hoari.",
|
||||
"horizon.agent.socket": "Socket: %s (eilañ ar munudoù evit e hent klok)",
|
||||
"horizon.agent.local_only": "Lec'hel hepken : an ajañsoù war an urzhiataer-mañ, biskoazh ar rouedad.",
|
||||
"Auto (%s nits)": "Emgefre (%s nits)",
|
||||
"Hides models behind opaque blocks. Entities update. Off with custom packs.": "Kuzhat a ra ar patromoù a-dreñv bloc'hoù dister. Hizivaat an ensavadurioù. Dilezet gant pakadoù personelaet.",
|
||||
"horizon.extras.repro_keys": "Berradennoù enrollañ",
|
||||
"horizon.extras.repro_keys.tooltip": "F3+R a grog pe a paouez gant un enrolladenn advouezhiañ ha F3+E a skriv e strollad. Diweredekaet dre ziouer : un enrolladenn a eil ar bed.",
|
||||
"horizon.agent.record_session": "Kregiñ gant an enrollañ",
|
||||
"horizon.agent.record_stop": "Paouez gant an enrollañ",
|
||||
"horizon.agent.export_repro": "Ezporzhiañ ar pakad advouezhiañ",
|
||||
"horizon.repro.started": "Kroget eo an enrollañ ; F3+R a harz anezhañ hag a skriv ar pakad.",
|
||||
"horizon.repro.stopped": "Paouezet gant an enrollañ : %s",
|
||||
"horizon.repro.bundle": "Pakad advouezhiañ : %s",
|
||||
"horizon.repro.no_recording": "N'eus enrolladenn ebet da ezporzhiañ c'hoazh.",
|
||||
"horizon.repro.replay_started": "Adc'hoari kroget : %s",
|
||||
"horizon.pack.addInfo": "Ouzhpennañ ur pakad arc'hwelioù adalek Modrinth",
|
||||
"horizon.pack.addWorking": "Goulenn Modrinth...",
|
||||
"horizon.pack.addNone": "N'eus bet kavet pakad arc'hwel ebet",
|
||||
"horizon.pack.addTitle": "Ouzhpennañ ur pakad arc'hwelioù",
|
||||
"horizon.pack.install": "Staliañ",
|
||||
"horizon.pack.installing": "O staliañ",
|
||||
"horizon.pack.installed": "Staliet",
|
||||
"horizon.pack.search": "Klask",
|
||||
"horizon.pack.searchHint": "Klask Modrinth...",
|
||||
"horizon.pack.filters": "Siloù",
|
||||
"horizon.pack.filter.realistic": "Gwirvoudel",
|
||||
"horizon.pack.filter.simplistic": "Eeun",
|
||||
"horizon.pack.filter.vanillaLike": "Heñvel ouzh ar vanilha",
|
||||
"horizon.pack.addFailed": "N'haller ket ouzhpennañ ar pakad : %s",
|
||||
"horizon.extras.header.cosmetics": "Kosmetikoù",
|
||||
"horizon.extras.cosmetics_mine": "Ma kosmetikoù",
|
||||
"horizon.extras.cosmetics_mine.tooltip": "Kuzhet : pep c'hoarier Horizon a wel ac'hanoc'h hep ho kosmetikoù, c'hwi en o zouez. Ar memes treuzfurmadur hag armel al lañser.",
|
||||
"horizon.extras.cosmetics_others": "Kosmetikoù ar c'hoarierien all",
|
||||
"horizon.extras.cosmetics_others.tooltip": "Ar pezh a vez gwisket gant ar c'hoarierien Horizon all : pep tra, o doareoù tikedenn anv hepken, pe netra. Kuzhet, ar c'hoari ne c'houlenn ket biskoazh petra a wiskont.",
|
||||
"horizon.extras.cosmetics_auras": "Auraoù ha roudoù tud all",
|
||||
"horizon.extras.cosmetics_auras.tooltip": "Auraoù ha roudoù a vez gwisket gant c'hoarierien all. Diweredekaet dre ziouer.",
|
||||
"horizon.extras.cosmetics.shown": "Diskouezet",
|
||||
"horizon.extras.cosmetics.hidden": "Kuzhet",
|
||||
"horizon.extras.cosmetics.name_tags": "Tikedennoù anvioù hepken"
|
||||
}
|
||||
@@ -0,0 +1,423 @@
|
||||
{
|
||||
"horizon.options.controller": "Kontroler",
|
||||
"horizon.options.vibration": "Vibracije",
|
||||
"horizon.options.adaptive_triggers": "Adaptivni okidači",
|
||||
"horizon.options.look_sensitivity": "Osjetljivost pogleda",
|
||||
"horizon.options.invert_x": "Obrnuti pogled po X",
|
||||
"horizon.options.invert_y": "Obrnuti pogled po Y",
|
||||
"horizon.options.sneak_button": "Dugme za šunjanje",
|
||||
"horizon.options.move_deadzone": "Mrtva zona kretanja",
|
||||
"horizon.options.look_deadzone": "Mrtva zona pogleda",
|
||||
"horizon.options.button_glyphs": "Dugmad Glyphs",
|
||||
"horizon.options.on_screen_keyboard": "Tastatura na ekranu",
|
||||
"horizon.options.lightbar.health": "Zdravlje",
|
||||
"horizon.options.lightbar.dimension": "Dimenzija",
|
||||
"horizon.options.unavailable": "Ova funkcija još nije dostupna u Horizon.",
|
||||
"horizon.options.search": "Postavke pretrage...",
|
||||
"horizon.pages.controller": "Postavke kontrolera",
|
||||
"horizon.pages.controller_binds": "Kontroler se vezuje",
|
||||
"horizon.pages.extras": "Horizon Dodaci",
|
||||
"horizon.pages.settings": "Horizon Postavke",
|
||||
"horizon.split.leave": "Odlazi",
|
||||
"horizon.pages.split_profiles": "ko igra?",
|
||||
"horizon.pages.music": "Muzika",
|
||||
"horizon.pages.music.menu": "Meni",
|
||||
"horizon.pages.music.creative": "Kreativno",
|
||||
"horizon.pages.music.underwater": "Pod vodom",
|
||||
"horizon.pages.music.end": "Kraj",
|
||||
"horizon.pages.music.boss": "Šefe",
|
||||
"horizon.pages.music.credits": "Zasluge",
|
||||
"horizon.pages.music.end_biomes": "Kraj bioma",
|
||||
"horizon.pages.music.other": "Ostala muzika",
|
||||
"horizon.pages.music.empty": "Nema muzičkih numera: zvuci igre se ne učitavaju.",
|
||||
"horizon.pages.music.tooltip": "Ugrađene numere, po situaciji: igrajte jednu sada ili isključite bilo koju da igra prestane da je bira.",
|
||||
"horizon.pages.settings.tooltip": "Horizon vlastite postavke: grafika, kontroleri, dodaci i modovi.",
|
||||
"horizon.pages.graphics.tooltip": "Grafika, jednostavno: svaka postavka govori koliko košta.",
|
||||
"horizon.pages.graphics_advanced.tooltip": "Svaka grafička postavka, Horizon je uključena, sa onim što svaka košta.",
|
||||
"horizon.pages.controller.tooltip": "Kontroleri: njihova dugmad, štapići, vibracije i navigacija u meniju.",
|
||||
"horizon.pages.extras.tooltip": "Opcioni dodaci, svi isključeni prema zadanim postavkama: igra ostaje vanila dok je ne uključite.",
|
||||
"horizon.pages.agent.tooltip": "Neka vaš AI agent igra: horizon-ctl i MCP klijente na ovom računaru.",
|
||||
"horizon.pages.split_profiles.tooltip": "Ko igra: profil koji se čuva u ovoj fascikli igre.",
|
||||
"horizon.pages.split_setup.tooltip": "Prozori i monitori, i ko gde igra.",
|
||||
"horizon.pages.shader_packs.tooltip": "Paketi shadera iz foldera shaderpacks: Horizon vlastiti i oni u shaders/ formatu. Jedan po jedan trči.",
|
||||
"horizon.pages.mods.tooltip": "Modovi napravljeni za Horizon, iz foldera horizon-mods. Svaki radi u sandboxu i ostaje isključen dok ga ne uključite.",
|
||||
"horizon.pages.open.graphics": "Grafika...",
|
||||
"horizon.pages.open.graphics_advanced": "Napredna grafika...",
|
||||
"horizon.pages.open.shader_packs": "Shader paketi...",
|
||||
"horizon.pages.open.controller": "Postavke kontrolera...",
|
||||
"horizon.pages.open.extras": "Dodaci...",
|
||||
"horizon.pages.open.mods": "Modovi...",
|
||||
"horizon.pages.open.agent": "AI agent...",
|
||||
"horizon.pages.open.horizon_graphics": "Horizon Grafika...",
|
||||
"horizon.pages.open.controller_binds": "Kontroler vezuje...",
|
||||
"horizon.pages.open.horizon_settings": "Horizon Postavke...",
|
||||
"horizon.pages.open.music": "muzika...",
|
||||
"horizon.mods.empty": "Bez modova: stavite .hmod fajlove u folder horizon-mods",
|
||||
"horizon.mods.stopped": " (zaustavljeno)",
|
||||
"horizon.mods.not_built": " (nije izgrađeno)",
|
||||
"horizon.mods.settings": "Postavke",
|
||||
"horizon.mods.in_world": " (ostavi svijet da se promijeni)",
|
||||
"horizon.mods.open_folder": "Otvorite Mod folder",
|
||||
"horizon.shader_packs.empty": "Nema paketa shadera: stavite ih u mapu shaderpacks",
|
||||
"horizon.shader_options.open": "Opcije shadera...",
|
||||
"horizon.shader_options.profile": "Profil",
|
||||
"horizon.shader_options.loading": "Čitanje opcija paketa shadera...",
|
||||
"horizon.agent.copy_details": "Kopiraj detalje veze",
|
||||
"horizon.multiplayer.join": "Pridružite se",
|
||||
"horizon.multiplayer.cancel_reconnecting": "Otkaži ponovno povezivanje",
|
||||
"horizon.multiplayer.join_friend": "Pridružite se prijatelju",
|
||||
"horizon.multiplayer.relay": "Relej (opciono)",
|
||||
"LOD Distance": "LOD Udaljenost",
|
||||
"Far Detail": "Daleki detalj",
|
||||
"Entity Culling": "Uništavanje entiteta",
|
||||
"Fog": "Magla",
|
||||
"Weather": "Vrijeme",
|
||||
"Animated Textures": "Animirane teksture",
|
||||
"Resolution Scale": "Skala rezolucije",
|
||||
"Upscaling": "Povećanje",
|
||||
"Paper White": "Papir bijeli",
|
||||
"Graphics API": "Grafički API",
|
||||
"Performance Overlay": "Preklapanje performansi",
|
||||
"Full Detail Distance": "Puna udaljenost do detalja",
|
||||
"Off": "Isključeno",
|
||||
"Unlimited": "Neograničeno",
|
||||
"Performance": "Performanse",
|
||||
"Balanced": "Balansirano",
|
||||
"Quality": "Kvaliteta",
|
||||
"Native": "Izvorno",
|
||||
"Full": "Pun",
|
||||
"Reduced": "Smanjena",
|
||||
"Efficient": "Efikasno",
|
||||
"Precise": "Precizno",
|
||||
"Auto (VSync)": "automatski (VSync)",
|
||||
"Immediate": "Odmah",
|
||||
"FPS and Graph": "FPS i Graf",
|
||||
"No cost": "Bez troškova",
|
||||
"Low cost": "Niska cijena",
|
||||
"Medium cost": "Srednji trošak",
|
||||
"High cost": "Visoka cijena",
|
||||
"Saves time": "Štedi vrijeme",
|
||||
"Graphics": "Grafika",
|
||||
"Done": "Gotovo",
|
||||
"This feature is not yet available in Horizon.": "Ova funkcija još nije dostupna u Horizon.",
|
||||
"Your display or system doesn't offer HDR output.": "Vaš ekran ili sistem ne nude HDR izlaz.",
|
||||
"Turn HDR on to use it.": "Uključite HDR da ga koristite.",
|
||||
"Your GPU or graphics API doesn't support it.": "Vaš GPU ili grafički API to ne podržava.",
|
||||
"%s chunks": "%s komada",
|
||||
"%s per frame": "%s po kadru",
|
||||
"%s MiB/frame": "%s MiB/okvir",
|
||||
"%s KiB/frame": "%s KiB/okvir",
|
||||
"Auto (%s)": "automatski (%s)",
|
||||
"Full-detail terrain range. LOD Distance can extend local worlds farther.": "Opseg terena sa punim detaljima. LOD Udaljenost može proširiti lokalne svjetove dalje.",
|
||||
"Coarse distant terrain in local worlds. Integrated GPUs stop at 128 chunks.": "Grubi udaljeni teren u lokalnim svjetovima. Integrisani GPU-ovi se zaustavljaju na 128 komada.",
|
||||
"Reduced draws far terrain coarser: faster on this integrated GPU.": "Smanjeno crtanje dalekog terena grublje: brže na ovom integrisanom GPU-u.",
|
||||
"Reduced draws far terrain coarser, for GPUs it slows down.": "Smanjeno crtanje dalekog terena je grublje, za GPU-ove usporava.",
|
||||
"Field of view. Wider shows more terrain at once.": "Vidno polje. Šire prikazuje više terena odjednom.",
|
||||
"Caps frames per second; a cap saves power and heat.": "Caps okvira u sekundi; kapa štedi energiju i toplotu.",
|
||||
"Waits for the display's refresh: no tearing, a little latency.": "Čeka osvježavanje ekrana: nema kidanja, malo kašnjenja.",
|
||||
"Size of menus and the HUD.": "Veličina menija i HUD-a.",
|
||||
"Sets the options below together. Changing one makes it Custom.": "Zajedno postavlja donje opcije. Promjenom jednog postaje prilagođeno.",
|
||||
"Lava, fire and sunlight shine brighter than white. Needs an HDR display.": "Lava, vatra i sunčeva svjetlost sijaju jače od bijele. Potreban je HDR ekran.",
|
||||
"Your display's darkest black. 0 for OLED; LCDs glow a little.": "Vaš ekran je najtamnije crn. 0 za OLED; LCD-i malo svijetle.",
|
||||
"How bright highlights get. Auto: the peak your system reports.": "Kako svetli naglasci postaju. Automatski: vrhunac o kojem vaš sistem prijavljuje.",
|
||||
"How bright white paper and menus look. Auto: your desktop's white.": "Kako izgledaju svijetli bijeli papir i meniji. Auto: vaša radna površina je bijela.",
|
||||
"How bright the HUD and menus are, against paper white.": "Koliko su svijetli HUD i meniji, naspram bijelog papira.",
|
||||
"How far mobs, crops and machines keep working. CPU time.": "Koliko mobovi, usjevi i mašine rade. CPU vrijeme.",
|
||||
"How far away mobs and items are drawn, as a share of normal.": "Koliko su udaljeni mobovi i predmeti, kao udio normalnog.",
|
||||
"Skips terrain hidden behind closed sections. Off costs a lot.": "Preskače teren skriven iza zatvorenih dijelova. Isključenje košta puno.",
|
||||
"Hides entities behind opaque blocks.": "Sakriva entitete iza neprozirnih blokova.",
|
||||
"No entity occlusion culling.": "Nema uklanjanja okluzije entiteta.",
|
||||
"CPU occlusion test runs this frame.": "CPU test okluzije pokreće ovaj okvir.",
|
||||
"Occlusion checks run on a worker thread.": "Provjere okluzije se pokreću na radnoj niti.",
|
||||
"Meshed sections uploaded per frame. Lower is smoother while loading.": "Mrežasti odjeljci otpremljeni po kadru. Donji dio je glatkiji tokom punjenja.",
|
||||
"Soft shadows in corners. Costs chunk building time only.": "Meke senke u uglovima. Košta samo vrijeme izgradnje komada.",
|
||||
"Smaller copies of block textures for distant terrain: less shimmer.": "Manje kopije blok tekstura za udaljeni teren: manje svjetlucanja.",
|
||||
"Blends grass and water colours across biomes when building chunks.": "Miješa travu i vodene boje po biomima prilikom izgradnje komada.",
|
||||
"Cloud layer: off, flat (fast) or 3D (fancy).": "Sloj oblaka: isključen, ravan (brzo) ili 3D (fensi).",
|
||||
"How far clouds reach, in chunks.": "Koliko daleko sežu oblaci, u komadima.",
|
||||
"Draws the sky, sun, moon and stars.": "Crta nebo, sunce, mjesec i zvijezde.",
|
||||
"Distance fog. Off shows the edge of the loaded world.": "Distance magla. Isključeno pokazuje ivicu učitanog svijeta.",
|
||||
"Draws rain and snow.": "Privlači kišu i snijeg.",
|
||||
"How far rain and snow fall around you.": "Koliko kiša i snijeg padaju oko vas.",
|
||||
"How many particles effects spawn.": "Koliko se efekata čestica pojavljuje.",
|
||||
"Round shadows under mobs and items.": "Okrugle sjene ispod mobova i predmeta.",
|
||||
"Leaves with see-through gaps. Off draws them solid.": "Listovi sa providnim prazninama. Off ih čvrsto privlači.",
|
||||
"Sorts water and glass more exactly behind each other.": "Tačnije sortira vodu i staklo jedno iza drugog.",
|
||||
"Which chunk rebuilds wait for the frame: none, nearby or yours.": "Koji komad obnavlja čeka na okvir: nijedan, u blizini ili vaš.",
|
||||
"Animates water, lava, fire and other moving textures.": "Animira vodu, lavu, vatru i druge pokretne teksture.",
|
||||
"World pixels per screen pixel. Below 100% is faster on the GPU.": "Svjetski pikseli po pikselu ekrana. Ispod 100% je brži na GPU-u.",
|
||||
"Smooths jagged edges. FXAA: softer. TAA: smoothest, moving things may trail.": "Zaglađuje nazubljene ivice. FXAA: mekše. TAA: najglađe, pokretne stvari mogu zaostajati.",
|
||||
"Renders the world smaller and rebuilds it with TAA. Faster, softer.": "Čini svijet manjim i obnavlja ga pomoću TAA. Brže, mekše.",
|
||||
"HDR output on an HDR display: lava, fire and sunlight shine brighter.": "HDR izlaz na HDR displeju: lava, vatra i sunčeva svetlost sijaju jače.",
|
||||
"How frames reach the screen while VSync is off.": "Kako okviri dolaze do ekrana dok je VSync isključen.",
|
||||
"Efficient sleeps until the next frame; Precise spins, like vanilla.": "Efikasno spavanje do sljedećeg kadra; Precizno okretanje, poput vanile.",
|
||||
"Fills the screen (borderless).": "Ispunjava ekran (bez ivica).",
|
||||
"Brightens dark places.": "Osvjetljava tamna mjesta.",
|
||||
"Lowers the frame rate when minimised, or idle too.": "Smanjuje brzinu kadrova kada je minimizirana ili u stanju mirovanja.",
|
||||
"Sways the view while walking.": "Ljulja pogled dok hodate.",
|
||||
"Fades newly loaded chunks in.": "Uklanja novoučitane komade.",
|
||||
"Darkens the screen's edges.": "Zatamnjuje ivice ekrana.",
|
||||
"Shows when the world saves.": "Prikazuje kada svijet spašava.",
|
||||
"Shows attack cooldown.": "Prikazuje hlađenje napada.",
|
||||
"60 FPS cap (30 in menus or unfocused), half the workers: less power.": "Ograničenje od 60 FPS (30 u menijima ili nefokusirano), pola radnika: manje energije.",
|
||||
"Threads that generate, light and mesh chunks. Next start.": "Niti koje stvaraju, lagane i mrežaste komade. Sljedeći početak.",
|
||||
"Vulkan, then DirectX 12 (Windows) or OpenGL (Linux) where it fails. Next start.": "Vulkan, zatim DirectX 12 (Windows) ili OpenGL (Linux) gdje ne uspije. Sljedeći početak.",
|
||||
"Water and glass in one buffer: fewer draw calls, a bit more VRAM. Next start.": "Voda i staklo u jednom baferu: manje poziva za povlačenje, malo više VRAM-a. Sljedeći početak.",
|
||||
"Mesh data sent to the GPU per frame. Lower is smoother while loading.": "Mrežni podaci se šalju GPU-u po okviru. Donji dio je glatkiji tokom punjenja.",
|
||||
"Frame rate and frame times over the game, with a graph.": "Brzina kadrova i vrijeme kadrova u igri, sa grafikonom.",
|
||||
"horizon.multiplayer.finding_friend": "Pronalaženje svijeta svog prijatelja...",
|
||||
"horizon.multiplayer.not_signed_in": "Ovaj server je u online modu. Prijavite se sa svojim Microsoft nalogom u Horizon pokretaču da mu se pridružite.",
|
||||
"horizon.multiplayer.invalid_address": "Nevažeća adresa servera: %s",
|
||||
"horizon.multiplayer.connected_friend_direct": "Povezani direktno sa vašim prijateljem...",
|
||||
"horizon.multiplayer.connected_friend_relay": "Povezani sa vašim prijateljem preko releja...",
|
||||
"General": "Generale",
|
||||
"Advanced": "Napredno",
|
||||
"Undo": "Poništi",
|
||||
"Search options": "Opcije pretraživanja",
|
||||
"Shortcut": "Prečica",
|
||||
"Distance": "Udaljenost",
|
||||
"Sky and weather": "Nebo i vrijeme",
|
||||
"Lighting and entities": "Rasvjeta i entiteti",
|
||||
"Textures": "Teksture",
|
||||
"Image": "Slika",
|
||||
"Chunk loading": "Učitavanje komada",
|
||||
"Culling": "Odbijanje",
|
||||
"Power": "Snaga",
|
||||
"Frames": "Okviri",
|
||||
"Output": "Izlaz",
|
||||
"Brightness": "Osvetljenost",
|
||||
"How far you see, the window and the HUD.": "Koliko daleko vidite, prozor i HUD.",
|
||||
"The sky and weather, lighting, textures and the image.": "Nebo i vrijeme, osvjetljenje, teksture i slika.",
|
||||
"Chunk loading, culling and power use.": "Učitavanje komada, uklanjanje i korištenje energije.",
|
||||
"How frames reach the screen, and the performance overlay.": "Kako okviri dolaze do ekrana i preklapanje performansi.",
|
||||
"Brighter-than-white output on an HDR display.": "Izlaz svjetliji od bijelog na HDR ekranu.",
|
||||
"Results for \"%s\"": "Rezultati za \"%s\"",
|
||||
"No settings match.": "Nijedna postavka se ne podudara.",
|
||||
"horizon.title.not_affiliated": "Nije povezan sa Mojangom ili Microsoftom",
|
||||
"horizon.extras.header.lighting": "Osvetljenje",
|
||||
"horizon.extras.header.third_person": "Treća osoba",
|
||||
"horizon.extras.header.particles": "Čestice",
|
||||
"horizon.extras.header.inventory": "Inventar",
|
||||
"horizon.extras.header.sound": "Zvuk",
|
||||
"horizon.extras.header.menus": "Meniji",
|
||||
"horizon.extras.dynamic_lights": "Dinamička svjetla",
|
||||
"horizon.extras.own_name_tag": "Oznaka s vlastitim imenom",
|
||||
"horizon.extras.hide_block_particles": "Sakrijte čestice razbijanja bloka",
|
||||
"horizon.extras.auto_reconnect": "Automatsko ponovno povezivanje",
|
||||
"horizon.extras.ui_sound_reserve": "Zadržite kanale za zvukove korisničkog interfejsa",
|
||||
"horizon.extras.music_page": "Muzička stranica",
|
||||
"horizon.extras.mouse_tweaks": "Kontrole podešavanja miša",
|
||||
"horizon.extras.mouse_tweaks_wheel": "Točkić za pomicanje pomiče stavke",
|
||||
"horizon.extras.sort": "Dugmad za sortiranje",
|
||||
"horizon.extras.sort_key": "Ključ za sortiranje",
|
||||
"horizon.extras.no_ai": "Nema AI",
|
||||
"horizon.extras.chat_animation": "Glatko ćaskanje",
|
||||
"horizon.extras.chat_indicator": "Indikator poruke",
|
||||
"horizon.extras.wheel_cycles_settings": "Točkić za pomicanje mijenja postavke",
|
||||
"horizon.extras.pack_browser": "Pregledač paketa resursa",
|
||||
"horizon.extras.fullbright.tooltip": "Prikažite blokove i entitete pri punom svjetlu, čak iu tamnim područjima.",
|
||||
"horizon.extras.dynamic_lights.tooltip": "Baklje i drugi izvori svjetlosti koji su držani, ispušteni ili zapaljeni osvjetljavaju blokove oko sebe.",
|
||||
"horizon.extras.own_name_tag.tooltip": "Prikazuje vaše ime iznad glave u trećem licu, kako ga vide drugi igrači. Skriveno kada server sakriva imena vašeg tima ili ste nevidljivi.",
|
||||
"horizon.extras.hide_block_particles.tooltip": "Sakriva čestice krhotina koje su izbile iz slomljenog bloka i raspale se s onog koji ste iskopavali. Ostale čestice ostaju.",
|
||||
"horizon.extras.auto_reconnect.tooltip": "Ponovo se pridružuje serveru nakon izgubljene veze ili ponovnog pokretanja, nikada nakon izbacivanja ili zabrane.",
|
||||
"horizon.extras.ui_sound_reserve.tooltip": "Zvukovi u svijetu ostavljaju slobodnim 16 od 247 zvučnih kanala, tako da njihova poplava (velika eksplozija) ne može utišati klikove menija.",
|
||||
"horizon.extras.music_page.tooltip": "Muzika i zvukovi dobijaju stranicu Music...: reproducirajte bilo koju ugrađenu numeru sada ili je isključite tako da igra prestane da je bira. Ništa se ne mijenja dok ne isključite numeru.",
|
||||
"horizon.extras.mouse_tweaks.tooltip": "Prevlačenjem udesno postavlja jedan po utoru, povlačenjem ulijevo skuplja zadržanu stavku, Shift + prevlačenjem ulijevo pomiče svaki slot.",
|
||||
"horizon.extras.mouse_tweaks_wheel.tooltip": "Dolje šalje jednu stavku utora na drugu stranu, gore vraća jednu nazad.",
|
||||
"horizon.extras.sort.tooltip": "Sortira inventar, škrinje, bačve, ender škrinje i kutije za šulkere u kreativnom redoslijedu kartica, spajajući hrpe.",
|
||||
"horizon.extras.sort_key.tooltip": "Sortira dio ispod kursora. Kliknite, a zatim pritisnite tipku; Escape ga odvezuje.",
|
||||
"horizon.extras.no_ai.tooltip": "Sakriva i isključuje svaku AI funkciju: kontrolu agenta, horizon-ctl i MCP servere. Prekidač lansera takođe.",
|
||||
"horizon.extras.agent_control.tooltip": "Vaš vlastiti AI agent može igrati ovu igru preko horizon-ctl ili MCP klijenta, samo na ovom računaru.",
|
||||
"horizon.extras.discord_presence.tooltip": "Prikazuje igranje Horizon na vašem Discord profilu dok Discord radi: meniji, za jednog igrača ili za više igrača, dimenziju i vrijeme igranja. Nikada ime svijeta ili adresu servera.",
|
||||
"Calibrate...": "Kalibriraj...",
|
||||
"Calibrate Anyway...": "Kalibriraj svejedno...",
|
||||
"Use Automatic Setup": "Koristite automatsko podešavanje",
|
||||
"Shortcut: %s": "Prečica: %s",
|
||||
"Next": "Sledeći",
|
||||
"HDR Calibration %s/%s: %s": "HDR kalibracija %s/%s: %s",
|
||||
"Sets the three below full screen, one test picture at a time.": "Postavlja tri ispod preko celog ekrana, jednu po jednu probnu sliku.",
|
||||
"A key that opens this screen from the game. Not bound at first.": "Taster koji otvara ovaj ekran iz igre. U početku nije vezan.",
|
||||
"Your display didn't say how bright it gets: calibrate to set it up.": "Vaš displej nije rekao koliko svetli: kalibrirajte da biste ga postavili.",
|
||||
"Already set up for your display. Only calibrate if HDR looks wrong.": "Već postavljeno za vaš ekran. Kalibrirajte samo ako HDR izgleda pogrešno.",
|
||||
"Puts Peak Brightness and Paper White back to your display's setup.": "Vraća Peak Brightness i Paper White u postavke vašeg ekrana.",
|
||||
"Set up for your display. Leave on Auto unless it looks wrong.": "Postavite za vaš ekran. Ostavite na Auto osim ako ne izgleda pogrešno.",
|
||||
"Lower it until the logo just disappears into the black.": "Spuštajte ga dok logo ne nestane u crno.",
|
||||
"Raise it until the logo just disappears into the bright square.": "Podignite ga dok logo ne nestane u svijetlom kvadratu.",
|
||||
"Make the card a white that's comfortable to look at for a long time, in the light you play in.": "Neka karta bude bela da je udobna za gledanje dugo vremena, na svetlu u kojem igrate.",
|
||||
"horizon.splitscreen.profiles.forget": "Zaboravi",
|
||||
"horizon.splitscreen.profiles.create": "Kreiraj",
|
||||
"horizon.splitscreen.profiles.you": " - ti",
|
||||
"horizon.splitscreen.profiles.forget_named": "Zaboravi %s",
|
||||
"horizon.splitscreen.profiles.previous": "Prethodno",
|
||||
"horizon.splitscreen.profiles.next": "Sledeći",
|
||||
"horizon.splitscreen.profiles.new_button": "Novi profil...",
|
||||
"horizon.splitscreen.profiles.forget_title": "Zaboravili ste profil?",
|
||||
"horizon.splitscreen.profiles.forget_leaves": "Napušta listu ove instance.",
|
||||
"horizon.splitscreen.profiles.forget_kept": "Svjetski napredak i postavke se čuvaju.",
|
||||
"horizon.splitscreen.profiles.new_title": "Novi profil",
|
||||
"horizon.splitscreen.profiles.name_hint": "Ime (3 do 16 slova, cifara, _)",
|
||||
"horizon.splitscreen.profiles.switch_title": "Promijeni profil",
|
||||
"horizon.splitscreen.profiles.offline_note": "Offline profili pripadaju ovoj instanci",
|
||||
"horizon.splitscreen.profiles.move": "Krećite se tamo gdje igrate",
|
||||
"horizon.splitscreen.profiles.move_place": "Premjestite se gdje igrate: %s",
|
||||
"horizon.friends.title": "Igrajte se s prijateljima",
|
||||
"horizon.friends.hint": "Prijatelji zalijepe kod iza dugmeta Prijatelji na naslovnom ekranu, u Direktnu vezu ili na Play stranicu pokretača.",
|
||||
"horizon.friends.copied": "Kopirano",
|
||||
"horizon.friends.copy_code": "Kopiraj kod",
|
||||
"horizon.friends.none_yet": "Ovdje još nema prijatelja.",
|
||||
"horizon.friends.here_now": "Evo sada: %s",
|
||||
"horizon.friends.share_intro": "Podijelite ovaj svijet iza pozivnog koda: otvara se na LAN, a prijatelji na internetu se pridružuju kodu. Nijedan naš server nije uključen.",
|
||||
"horizon.friends.start_sharing": "Počnite dijeliti",
|
||||
"horizon.friends.troubleshooting": "Rješavanje problema...",
|
||||
"horizon.friends.stopped": "Zaustavljeno je dijeljenje pozivnog koda.",
|
||||
"horizon.friends.short_code_changed": "Neko je nastavio pokušavati s pogrešnim kratkim kodom, pa se to promijenilo.",
|
||||
"horizon.friends.wrong_code": "Neko je probao pogrešan kod.",
|
||||
"horizon.friends.code_ready": "Vaš pozivni kod je spreman: Meni igre, Igrajte se sa prijateljima. Kopirajte ga i pošaljite svojim prijateljima.",
|
||||
"horizon.friends.share_failed": "Ne mogu dijeliti svijet: %s",
|
||||
"horizon.friends.finding_route": "Pronalaženje načina na koji prijatelji mogu doći do vas…",
|
||||
"horizon.osk.delete": "Izbriši",
|
||||
"horizon.osk.type": "Tip",
|
||||
"horizon.osk.symbols": "Simboli",
|
||||
"horizon.osk.close": "Zatvori",
|
||||
"horizon.extras.chat_animation.tooltip": "Nova linija ćaskanja klizi s lijeve strane dok se gasi, umjesto da izgleda kao cijela.",
|
||||
"horizon.extras.chat_indicator.tooltip": "Traka u boji lijevo od linije za ćaskanje.",
|
||||
"horizon.extras.wheel_cycles_settings.tooltip": "Točkić za pomeranje preko dugmeta u podešavanjima menja svoju vrednost, kao u vaniliji. Isključeno, kotačić samo pomiče listu.",
|
||||
"horizon.extras.pack_browser.tooltip": "Select Resource Packs dobija dugme Dodaj koje pretražuje Modrinth i instalira paket u fasciklu sa paketima. Isključeno, igra nikada ne kontaktira Modrinth.",
|
||||
"horizon.extras.splitscreen.tooltip": "U svijetu se drugi kontrolor može pridružiti kao novi igrač: pritisnite A kada to zatraži, a zatim odaberite profil i gdje ćete igrati.",
|
||||
"horizon.splitscreen.setup.monitor_unknown": "monitor",
|
||||
"horizon.splitscreen.setup.window": "Prozor %s",
|
||||
"horizon.splitscreen.setup.new_window": "Novi prozor",
|
||||
"horizon.splitscreen.setup.fill_monitor": "Popuni %s",
|
||||
"horizon.splitscreen.setup.done": "Gotovo",
|
||||
"horizon.splitscreen.setup.off": "Isključeno",
|
||||
"horizon.splitscreen.setup.player": "Igrač %s",
|
||||
"horizon.splitscreen.setup.revert": "Vrati",
|
||||
"horizon.splitscreen.setup.apply": "Prijavite se",
|
||||
"horizon.splitscreen.setup.warning.empty_main": "Niko ne igra u prozoru 1: skriva se",
|
||||
"horizon.splitscreen.setup.warning.empty_close": "Niko ne igra u prozoru %s: zatvara se na Apply",
|
||||
"horizon.splitscreen.setup.warning.empty_new": "Niko ne igra u prozoru %s: neće se otvoriti",
|
||||
"horizon.splitscreen.setup.warning.on_main": "Prozor %s ispunjava monitor prozora 1: njegovi igrači igraju u prozoru 1",
|
||||
"horizon.splitscreen.setup.warning.unplugged": "Monitor prozora %s nije povezan: njegovi igrači igraju u prozoru 1",
|
||||
"horizon.splitscreen.setup.status.off": "Splitscreen je isključen.",
|
||||
"horizon.splitscreen.setup.status.enable_hint": "Uključite ga, a zatim pritisnite dugme na drugom kontroleru u svetu.",
|
||||
"horizon.splitscreen.setup.status.join_hint": "Pritisnite A da se pridružite i odaberete profil.",
|
||||
"horizon.splitscreen.setup.status.idle": "Splitscreen u mirovanju",
|
||||
"horizon.splitscreen.setup.status.alone": "Nema drugih domaćih igrača.",
|
||||
"horizon.splitscreen.setup.status.solo_controls": "Solo kontrole i povratne informacije kontrolera su nepromijenjene.",
|
||||
"horizon.splitscreen.setup.window_empty": "Prozor %s: prazan",
|
||||
"horizon.splitscreen.setup.note.select": "Kliknite na plejer ili ga prevucite na prozor ili monitor.",
|
||||
"horizon.splitscreen.setup.note.apply": "Prijavite se da igrate na ovaj način, vratite se da poništite.",
|
||||
"horizon.splitscreen.setup.note.place": "Gdje bi %s trebao igrati?",
|
||||
"horizon.splitscreen.setup.this_player": "ovaj igrač",
|
||||
"horizon.splitscreen.setup.switch_disabled": "Splitscreen se gasi kada drugi odu (njihov meni za pauzu).",
|
||||
"horizon.splitscreen.setup.window_place": "Prozor %s (%s od %s)",
|
||||
"horizon.splitscreen.setup.names": "Imena",
|
||||
"horizon.splitscreen.setup.identify": "Identifikujte",
|
||||
"horizon.splitscreen.setup.layout.two": "2 dijeljenja: %s",
|
||||
"horizon.splitscreen.setup.layout.three": "3 dijeljenja: %s",
|
||||
"horizon.splitscreen.setup.layout.two.1": "Rame uz rame",
|
||||
"horizon.splitscreen.setup.layout.two.2": "Gornji i donji deo",
|
||||
"horizon.splitscreen.setup.layout.three.0": "Jedan širok na vrhu",
|
||||
"horizon.splitscreen.setup.layout.three.1": "Jedan visok sa leve strane",
|
||||
"horizon.splitscreen.setup.layout.three.2": "Rame uz rame",
|
||||
"horizon.splitscreen.setup.help.player": "Kliknite ili prevucite %s da ih premjestite.",
|
||||
"horizon.splitscreen.setup.help.layout_auto": "%s (uporedo kada je prozor širok). Pritisnite za promjenu.",
|
||||
"horizon.splitscreen.setup.help.layout": "%s. Pritisnite za promjenu.",
|
||||
"horizon.splitscreen.setup.help.switch": "Splitscreen za ovaj računar, uključen ili isključen.",
|
||||
"horizon.splitscreen.setup.help.identify": "Pogled svakog igrača pokazuje u kojem se prozoru nalazi.",
|
||||
"horizon.splitscreen.setup.help.names": "Ime svakog igrača u uglu njegovog pogleda.",
|
||||
"horizon.splitscreen.setup.help.revert": "Poništite promjene koje još nisu primijenjene.",
|
||||
"horizon.splitscreen.setup.help.apply": "Igrajte onako kako je prikazano na karti.",
|
||||
"horizon.splitscreen.setup.help.unchanged": "Još se ništa nije promijenilo.",
|
||||
"horizon.splitscreen.prompt.controller_connected": "Kontroler povezan",
|
||||
"horizon.splitscreen.prompt.controller_disconnected": "Kontroler je isključen",
|
||||
"horizon.splitscreen.prompt.controller_disconnected.hint": "Ponovo ga povežite ili pritisnite dugme na drugom",
|
||||
"horizon.splitscreen.prompt.join.one": "%s se želi pridružiti",
|
||||
"horizon.splitscreen.prompt.join.many": "%s kontrolori se žele pridružiti",
|
||||
"horizon.splitscreen.prompt.join.yes": "Pridružite se",
|
||||
"horizon.splitscreen.prompt.join.as_p1": "Igrajte kao P1",
|
||||
"horizon.splitscreen.prompt.join.no": "br",
|
||||
"horizon.splitscreen.prompt.lost": "%s: kontroler isključen",
|
||||
"horizon.splitscreen.prompt.lost.use_another": "Koristi drugu",
|
||||
"horizon.splitscreen.prompt.lost.leave": "Odlazi",
|
||||
"horizon.splitscreen.setup.help.give_up_pad": "Vaš kontrolor prestaje da vas vozi i nudi mu se pridruživanje (A).",
|
||||
"horizon.splitscreen.setup.note.held_at": "%s do %s: A ispušta je ovdje, B vraća.",
|
||||
"horizon.splitscreen.setup.note.held": "%s podignuto: lijevo/desno bira gdje, A pada, B vraća nazad.",
|
||||
"Hides models behind opaque blocks. Async checks off-thread; entities tick.": "Skriva modele iza neprozirnih blokova. Async provjerava off-thread; entiteti otkucaju.",
|
||||
"Block Entities": "Blokirajte entitete",
|
||||
"Reuses settled boxes; lid movement stays animated.": "Ponovno koristi postavljene kutije; pokreti poklopca ostaju animirani.",
|
||||
"Signs": "Znakovi",
|
||||
"Reuses sign text until text, light, or font changes.": "Ponovo koristi potpisni tekst dok se ne promijeni tekst, svjetlo ili font.",
|
||||
"Reuses still pots; break wobble and sherd changes redraw.": "Ponovno koristi lonce za mirovanje; prekinuti kolebanje i promjene u komadu ponovo nacrtati.",
|
||||
"Bells": "Zvona",
|
||||
"Reuses still bells; ringing stays animated.": "Ponovno koristi zvona za mirovanje; zvono ostaje animirano.",
|
||||
"Chests": "Škrinje",
|
||||
"Reuses closed chests; moving lids stay animated.": "Ponovno koristi zatvorene škrinje; pokretni poklopci ostaju animirani.",
|
||||
"Banners": "Banneri",
|
||||
"Reuses poles; flags and pattern layers still update.": "Ponovo koristi stubove; zastavice i slojevi uzoraka se i dalje ažuriraju.",
|
||||
"Copper Golem Statues": "Statue od bakrenog golema",
|
||||
"Reuses statue geometry until its block state changes.": "Ponovo koristi geometriju statue dok se stanje bloka ne promijeni.",
|
||||
"Every leaf face. Vanilla's fancy leaves.": "Svaki list lice. Vanilini fensi listovi.",
|
||||
"Keeps fine plants in high-res packs from fading far away.": "Čuva fine biljke u pakovanjima visoke rezolucije da ne izblijede.",
|
||||
"Screenshot Quality": "Kvaliteta snimka zaslona",
|
||||
"F2 screenshots at this many times the game's resolution. Higher takes longer.": "F2 screenshotovi na ovoj rezoluciji koja je mnogo puta veća od igre. Više traje duže.",
|
||||
"Frame Generation": "Generacija okvira",
|
||||
"Shows a made-up frame between each two real ones: smoother, a little more lag.": "Prikazuje napravljeni okvir između svaka dva stvarna: glatkiji, malo više zaostajanja.",
|
||||
"Reuses the pack shadow map when sun, view and world match. Off by default.": "Ponovo koristi mapu senki paketa kada se poklope sunce, pogled i svijet. Podrazumevano isključeno.",
|
||||
"Find BlueMap": "Pronađite BlueMap",
|
||||
"On servers, finds their BlueMap web map for far terrain. Next join.": "Na serverima pronalazi njihovu BlueMap web kartu za daleki teren. Sljedeći spoj.",
|
||||
"How far around you BlueMap tiles are downloaded. Next join.": "Koliko daleko oko vas se preuzimaju BlueMap pločice. Sljedeći spoj.",
|
||||
"Synchronous": "Sinhroni",
|
||||
"Asynchronous": "Asinhroni",
|
||||
"Leaves fully inside a canopy draw solid: fewer see-through layers.": "Listovi u potpunosti unutar krošnje crtaju čvrsto: manje providnih slojeva.",
|
||||
"Leaves with one open side draw solid too: faster, chunkier edges.": "Listovi s jednom otvorenom stranom također crtaju čvrsto: brže, zdepanije ivice.",
|
||||
"Drops faces between leaves: faster, but gaps look through.": "Spušta lica između listova: brže, ali praznine gledaju kroz njih.",
|
||||
"Hotbar: Previous Slot": "Hotbar: prethodni slot",
|
||||
"horizon.agent.connected.one": "Povezano: 1 veza agenta",
|
||||
"horizon.agent.connected.many": "Povezano: %s veze agenta",
|
||||
"horizon.agent.connected.one_ago": "Povezano: 1 veza agenta, zadnja komanda prije %s s",
|
||||
"horizon.agent.connected.many_ago": "Povezano: %s veze agenta, zadnja komanda prije %s s",
|
||||
"horizon.agent.waiting": "Čekam agenta.",
|
||||
"horizon.agent.off": "Isključeno: agenti ne mogu doći do ove igre.",
|
||||
"horizon.agent.session_opened": "Otvoreno za ovu sesiju od strane programa koji je pokrenuo igru.",
|
||||
"horizon.agent.socket": "Socket: %s (kopirajte detalje za njegovu punu putanju)",
|
||||
"horizon.agent.local_only": "Samo lokalno: agenti na ovom računaru, nikada mreža.",
|
||||
"%s nits": "%s gnjida",
|
||||
"Auto (%s nits)": "automatski (%s gnjida)",
|
||||
"%.2f nits": "%.2f gnjida",
|
||||
"Hides models behind opaque blocks. Entities update. Off with custom packs.": "Skriva modele iza neprozirnih blokova. Ažuriranje entiteta. Isključeno sa prilagođenim paketima.",
|
||||
"horizon.extras.repro_keys": "Prečice za snimanje",
|
||||
"horizon.extras.repro_keys.tooltip": "F3+R pokreće ili zaustavlja repro snimanje, a F3+E upisuje njegov paket. Podrazumevano isključeno: snimak kopira svijet.",
|
||||
"horizon.agent.record_session": "Započnite snimanje sesije",
|
||||
"horizon.agent.record_stop": "Zaustavi snimanje sesije",
|
||||
"horizon.agent.export_repro": "Izvezi Repro Bundle",
|
||||
"horizon.repro.started": "Snimanje je počelo; F3+R ga zaustavlja i upisuje paket.",
|
||||
"horizon.repro.stopped": "Snimanje zaustavljeno: %s",
|
||||
"horizon.repro.bundle": "Repro paket: %s",
|
||||
"horizon.repro.no_recording": "Još uvijek nema snimka za izvoz.",
|
||||
"horizon.repro.replay_started": "Repriza je počela: %s",
|
||||
"horizon.pack.addInfo": "Dodajte paket resursa iz Modrintha",
|
||||
"horizon.pack.addWorking": "Pitam Modrintha...",
|
||||
"horizon.pack.addNone": "Nije pronađen nijedan paket resursa",
|
||||
"horizon.pack.addTitle": "Dodajte paket resursa",
|
||||
"horizon.pack.install": "Instaliraj",
|
||||
"horizon.pack.installing": "Instaliranje",
|
||||
"horizon.pack.installed": "Instalirano",
|
||||
"horizon.pack.search": "Traži",
|
||||
"horizon.pack.searchHint": "Pretraži Modrinth...",
|
||||
"horizon.pack.filters": "Filteri",
|
||||
"horizon.pack.filter.realistic": "Realističan",
|
||||
"horizon.pack.filter.simplistic": "Pojednostavljeno",
|
||||
"horizon.pack.filter.vanillaLike": "Nalik vaniliji",
|
||||
"horizon.pack.addFailed": "Paket se nije mogao dodati: %s",
|
||||
"horizon.extras.header.cosmetics": "Kozmetika",
|
||||
"horizon.extras.cosmetics_mine": "Moja kozmetika",
|
||||
"horizon.extras.cosmetics_mine.tooltip": "Skriveno: svaki Horizon igrač vas vidi bez vaše kozmetike, uključujući i vas. Isti prekidač kao Ormar lansera.",
|
||||
"horizon.extras.cosmetics_others": "Kozmetika drugih igrača",
|
||||
"horizon.extras.cosmetics_others.tooltip": "Šta drugi Horizon igrači nose: sve, samo stilove oznaka sa imenom ili ništa. Skriveno, igra nikad ne pita šta nose.",
|
||||
"horizon.extras.cosmetics_auras": "Aure i tragovi drugih",
|
||||
"horizon.extras.cosmetics_auras.tooltip": "Aure i staze koje drugi igrači nose. Podrazumevano isključeno.",
|
||||
"horizon.extras.cosmetics.shown": "Prikazano",
|
||||
"horizon.extras.cosmetics.hidden": "Skriveno",
|
||||
"horizon.extras.cosmetics.name_tags": "Samo oznake sa imenom"
|
||||
}
|
||||
@@ -0,0 +1,471 @@
|
||||
{
|
||||
"horizon.options.controller": "Controlador",
|
||||
"horizon.options.vibration": "Vibració",
|
||||
"horizon.options.adaptive_triggers": "Disparadors adaptatius",
|
||||
"horizon.options.lightbar": "Barra de llums",
|
||||
"horizon.options.look_sensitivity": "Sensibilitat de la mirada",
|
||||
"horizon.options.invert_x": "Invertir la mirada X",
|
||||
"horizon.options.invert_y": "Invertir la mirada Y",
|
||||
"horizon.options.sneak_button": "Botó d'ajupir-se",
|
||||
"horizon.options.move_deadzone": "Zona morta del moviment",
|
||||
"horizon.options.look_deadzone": "Zona morta de la vista",
|
||||
"horizon.options.button_glyphs": "Glifos de botons",
|
||||
"horizon.options.on_screen_keyboard": "Teclat en pantalla",
|
||||
"horizon.options.chat_delay": "Retard de xat",
|
||||
"horizon.options.lightbar.health": "Salut",
|
||||
"horizon.options.lightbar.dimension": "Dimensió",
|
||||
"horizon.options.glyphs.auto": "Automàtic",
|
||||
"horizon.options.keyboard.auto": "Automàtic",
|
||||
"horizon.options.unavailable": "Aquesta funció encara no està disponible a Horizon.",
|
||||
"horizon.options.search": "Configuració de cerca...",
|
||||
"horizon.pages.shader_packs": "Paquets Shader",
|
||||
"horizon.pages.shader_options": "Opcions d'ombra",
|
||||
"horizon.pages.controller": "Configuració del controlador",
|
||||
"horizon.pages.controller_binds": "El controlador enllaça",
|
||||
"horizon.pages.settings": "Configuració d'Horizon",
|
||||
"horizon.pages.agent": "Agent d'IA",
|
||||
"horizon.split.leave": "marxar",
|
||||
"horizon.pages.split_settings": "Configuració de pantalla dividida",
|
||||
"horizon.pages.split_profiles": "Qui juga?",
|
||||
"horizon.pages.split_setup": "Configuració de pantalla dividida",
|
||||
"horizon.pages.music": "Música",
|
||||
"horizon.pages.music.menu": "Menú",
|
||||
"horizon.pages.music.creative": "Creatiu",
|
||||
"horizon.pages.music.underwater": "Sota l'aigua",
|
||||
"horizon.pages.music.end": "El final",
|
||||
"horizon.pages.music.boss": "Cap",
|
||||
"horizon.pages.music.credits": "Crèdits",
|
||||
"horizon.pages.music.overworld_biomes": "Biomes del sobremón",
|
||||
"horizon.pages.music.nether_biomes": "Biomes inferiors",
|
||||
"horizon.pages.music.end_biomes": "Fi dels biomes",
|
||||
"horizon.pages.music.other": "Altres músiques",
|
||||
"horizon.pages.music.empty": "Sense pistes de música: els sons del joc no es carreguen.",
|
||||
"horizon.pages.music.tooltip": "Les pistes integrades, per situació: juga-ne una ara o desactiva-ne qualsevol perquè el joc deixi de triar-ne.",
|
||||
"horizon.pages.settings.tooltip": "Configuració pròpia d'Horizon: gràfics, controladors, extres i modificacions.",
|
||||
"horizon.pages.graphics.tooltip": "Gràfics, senzillament: cada paràmetre diu el que costa.",
|
||||
"horizon.pages.graphics_advanced.tooltip": "Tots els paràmetres gràfics, inclòs Horizon, amb el que costa cadascun.",
|
||||
"horizon.pages.controller.tooltip": "Controladors: els seus botons, pals, vibració i navegació per menús.",
|
||||
"horizon.pages.extras.tooltip": "Addicions opcionals, totes desactivades de manera predeterminada: el joc es manté de vainilla fins que en activeu un.",
|
||||
"horizon.pages.agent.tooltip": "Deixa que jugui el teu propi agent d'IA: clients horizon-ctl i MCP en aquest ordinador.",
|
||||
"horizon.pages.split_profiles.tooltip": "Qui juga: un perfil guardat en aquesta carpeta del joc.",
|
||||
"horizon.pages.split_setup.tooltip": "Les finestres i els monitors, i qui juga on.",
|
||||
"horizon.pages.shader_packs.tooltip": "Paquets shader de la carpeta shaderpacks: els propis d'Horizon i els del format shaders/. Un corre a la vegada.",
|
||||
"horizon.pages.mods.tooltip": "Mods fets per a Horizon, des de la carpeta horizon-mods. Cadascun funciona en una caixa de sorra i es manté apagat fins que l'enceneu.",
|
||||
"horizon.pages.open.graphics": "Gràfics...",
|
||||
"horizon.pages.open.graphics_advanced": "Gràfics avançats...",
|
||||
"horizon.pages.open.shader_packs": "Paquets d'ombres...",
|
||||
"horizon.pages.open.controller": "Configuració del controlador...",
|
||||
"horizon.pages.open.split_setup": "Pantalla dividida...",
|
||||
"horizon.pages.open.extras": "Extres...",
|
||||
"horizon.pages.open.agent": "Agent d'IA...",
|
||||
"horizon.pages.open.horizon_graphics": "Gràfics d'Horizon...",
|
||||
"horizon.pages.open.controller_binds": "El controlador s'enllaça...",
|
||||
"horizon.pages.open.horizon_settings": "Configuració d'Horizon...",
|
||||
"horizon.pages.open.music": "Música...",
|
||||
"horizon.mods.empty": "Sense modificacions: poseu fitxers .hmod a la carpeta horizon-mods",
|
||||
"horizon.mods.stopped": " (aturat)",
|
||||
"horizon.mods.not_built": " (No construït)",
|
||||
"horizon.mods.dev": " (Desenvolupament)",
|
||||
"horizon.mods.settings": "Configuració",
|
||||
"horizon.mods.in_world": " (deixar el món per canviar)",
|
||||
"horizon.mods.open_folder": "Obriu la carpeta de modificacions",
|
||||
"horizon.shader_packs.empty": "Sense paquets d'ombres: col·loqueu-los a la carpeta shaderpacks",
|
||||
"horizon.shader_options.open": "Opcions d'ombrejat...",
|
||||
"horizon.shader_options.profile": "Perfil",
|
||||
"horizon.shader_options.loading": "Llegint les opcions del paquet shader...",
|
||||
"horizon.agent.copy_details": "Copia els detalls de la connexió",
|
||||
"horizon.multiplayer.join": "Uneix-te",
|
||||
"horizon.multiplayer.cancel_reconnecting": "Cancel·la la tornada a connectar",
|
||||
"horizon.multiplayer.join_friend": "Uneix-te a un amic",
|
||||
"horizon.multiplayer.invite_code": "Codi d'invitació",
|
||||
"horizon.multiplayer.relay": "Relé (opcional)",
|
||||
"Preset": "Preestablert",
|
||||
"LOD Distance": "Distància LOD",
|
||||
"Far Detail": "Detall llunyà",
|
||||
"Cave Culling": "Culling de coves",
|
||||
"Entity Culling": "Culling d'entitats",
|
||||
"Chunk Updates": "Actualitzacions de blocs",
|
||||
"Upload Budget": "Carregar pressupost",
|
||||
"Sky": "Cel",
|
||||
"Fog": "Boira",
|
||||
"Weather": "El temps",
|
||||
"Animated Textures": "Textures animades",
|
||||
"Present Mode": "Mode present",
|
||||
"Frame Pacing": "Marc de ritme",
|
||||
"Worker Threads": "Fils de treball",
|
||||
"Resolution Scale": "Escala de resolució",
|
||||
"Anti-aliasing": "Antialiasing",
|
||||
"Upscaling": "Ampliació d'escala",
|
||||
"Paper White": "Paper blanc",
|
||||
"Peak Brightness": "Lluminositat màxima",
|
||||
"Black Level": "Nivell negre",
|
||||
"UI Brightness": "Brillantor de la IU",
|
||||
"Battery Mode": "Mode de bateria",
|
||||
"Graphics API": "API de gràfics",
|
||||
"Translucent Batching": "Lots translúcids",
|
||||
"Performance Overlay": "Superposició de rendiment",
|
||||
"Full Detail Distance": "Distància de detall complet",
|
||||
"On": "Encès",
|
||||
"Off": "Apagat",
|
||||
"Unlimited": "Il·limitat",
|
||||
"Auto": "Automàtic",
|
||||
"Custom": "Personalitzat",
|
||||
"Performance": "Rendiment",
|
||||
"Balanced": "Equilibrat",
|
||||
"Quality": "Qualitat",
|
||||
"Ultra Performance": "Ultra rendiment",
|
||||
"Native": "Nadiu",
|
||||
"Full": "Complet",
|
||||
"Reduced": "Reduït",
|
||||
"Efficient": "Eficient",
|
||||
"Precise": "Precís",
|
||||
"Auto (VSync)": "Automàtic (VSync)",
|
||||
"Mailbox": "Bústia de correu",
|
||||
"Immediate": "Immediatament",
|
||||
"FPS and Graph": "FPS i gràfic",
|
||||
"No cost": "Sense cost",
|
||||
"Low cost": "Baix cost",
|
||||
"Medium cost": "Cost mitjà",
|
||||
"High cost": "Alt cost",
|
||||
"Saves time": "Estalvia temps",
|
||||
"Graphics": "Gràfics",
|
||||
"Done": "Fet",
|
||||
"This feature is not yet available in Horizon.": "Aquesta funció encara no està disponible a Horizon.",
|
||||
"Your display or system doesn't offer HDR output.": "La vostra pantalla o sistema no ofereixen sortida HDR.",
|
||||
"Turn HDR on to use it.": "Activa HDR per utilitzar-lo.",
|
||||
"Your GPU or graphics API doesn't support it.": "La vostra GPU o API de gràfics no ho admet.",
|
||||
"%s chunks": "%s trossos",
|
||||
"%s per frame": "%s per fotograma",
|
||||
"Auto (%s)": "Automàtic (%s)",
|
||||
"Full-detail terrain range. LOD Distance can extend local worlds farther.": "Gamma de terreny amb tots els detalls. La distància LOD pot estendre els mons locals més lluny.",
|
||||
"Coarse distant terrain in local worlds. Integrated GPUs stop at 128 chunks.": "Terreny llunyà gruixut en mons locals. Les GPU integrades s'aturen a 128 fragments.",
|
||||
"Reduced draws far terrain coarser: faster on this integrated GPU.": "Dibuixos reduïts molt llunyans més gruixuts: més ràpid en aquesta GPU integrada.",
|
||||
"Reduced draws far terrain coarser, for GPUs it slows down.": "Els dibuixos reduïts són molt més gruixuts, per a les GPU s'alenteix.",
|
||||
"Field of view. Wider shows more terrain at once.": "Camp de visió. Més ample mostra més terreny alhora.",
|
||||
"Caps frames per second; a cap saves power and heat.": "Caps fotogrames per segon; una tapa estalvia energia i calor.",
|
||||
"Waits for the display's refresh: no tearing, a little latency.": "Espera que la pantalla s'actualitzi: sense trencament, una mica de latència.",
|
||||
"Size of menus and the HUD.": "Mida dels menús i l'HUD.",
|
||||
"Sets the options below together. Changing one makes it Custom.": "Estableix les opcions següents juntes. Canviar-ne un el fa personalitzat.",
|
||||
"Lava, fire and sunlight shine brighter than white. Needs an HDR display.": "La lava, el foc i la llum del sol brillen més que el blanc. Necessita una pantalla HDR.",
|
||||
"Your display's darkest black. 0 for OLED; LCDs glow a little.": "La pantalla és el negre més fosc. 0 per a OLED; Els LCD brillen una mica.",
|
||||
"How bright highlights get. Auto: the peak your system reports.": "Com es fan els reflexos brillants. Automàtic: el pic que informa el vostre sistema.",
|
||||
"How bright white paper and menus look. Auto: your desktop's white.": "Quin aspecte brillant del paper blanc i dels menús. Automàtic: el teu escriptori és blanc.",
|
||||
"How bright the HUD and menus are, against paper white.": "Què brillants són l'HUD i els menús, contra el paper blanc.",
|
||||
"How far mobs, crops and machines keep working. CPU time.": "Fins on segueixen treballant les turbes, els conreus i les màquines. Temps de CPU.",
|
||||
"How far away mobs and items are drawn, as a share of normal.": "A quina distància es dibuixen les turbes i els articles, com a part de la normalitat.",
|
||||
"Skips terrain hidden behind closed sections. Off costs a lot.": "Salta el terreny amagat darrere de seccions tancades. Off costa molt.",
|
||||
"Hides entities behind opaque blocks.": "Amaga les entitats darrere de blocs opacs.",
|
||||
"No entity occlusion culling.": "Cap eliminació d'oclusió d'entitats.",
|
||||
"CPU occlusion test runs this frame.": "La prova d'oclusió de la CPU executa aquest marc.",
|
||||
"Occlusion checks run on a worker thread.": "Les comprovacions d'oclusió s'executen en un fil de treball.",
|
||||
"Meshed sections uploaded per frame. Lower is smoother while loading.": "Seccions de malla penjades per fotograma. La part inferior és més suau mentre es carrega.",
|
||||
"Soft shadows in corners. Costs chunk building time only.": "Ombres suaus a les cantonades. Només costa una part del temps de construcció.",
|
||||
"Smaller copies of block textures for distant terrain: less shimmer.": "Còpies més petites de textures de bloc per a terrenys llunyans: menys brillantor.",
|
||||
"Blends grass and water colours across biomes when building chunks.": "Combina els colors de l'herba i l'aigua entre els biomes quan es construeixen trossos.",
|
||||
"Cloud layer: off, flat (fast) or 3D (fancy).": "Capa de núvol: apagada, plana (ràpida) o 3D (de luxe).",
|
||||
"How far clouds reach, in chunks.": "Fins on arriben els núvols, a trossos.",
|
||||
"Draws the sky, sun, moon and stars.": "Dibuixa el cel, el sol, la lluna i les estrelles.",
|
||||
"Distance fog. Off shows the edge of the loaded world.": "Boira de distància. Off mostra la vora del món carregat.",
|
||||
"Draws rain and snow.": "Dibuixa pluja i neu.",
|
||||
"How far rain and snow fall around you.": "A quina distància cau la pluja i la neu al teu voltant.",
|
||||
"How many particles effects spawn.": "Quants efectes de partícules generen.",
|
||||
"Round shadows under mobs and items.": "Ombres rodones sota turbes i objectes.",
|
||||
"Leaves with see-through gaps. Off draws them solid.": "Fulles amb buits transparents. Off els dibuixa sòlids.",
|
||||
"Sorts water and glass more exactly behind each other.": "Classifica l'aigua i el vidre més exactament l'un darrere l'altre.",
|
||||
"Which chunk rebuilds wait for the frame: none, nearby or yours.": "Quin tros reconstrueix esperar el marc: cap, a prop o teu.",
|
||||
"Animates water, lava, fire and other moving textures.": "Anima l'aigua, la lava, el foc i altres textures en moviment.",
|
||||
"World pixels per screen pixel. Below 100% is faster on the GPU.": "Píxels mundials per píxel de pantalla. Per sota del 100% és més ràpid a la GPU.",
|
||||
"Smooths jagged edges. FXAA: softer. TAA: smoothest, moving things may trail.": "Allisa les vores dentades. FXAA: més suau. TAA: més suau, les coses en moviment poden seguir.",
|
||||
"Renders the world smaller and rebuilds it with TAA. Faster, softer.": "Redueix el món i el reconstrueix amb TAA. Més ràpid, més suau.",
|
||||
"HDR output on an HDR display: lava, fire and sunlight shine brighter.": "Sortida HDR en una pantalla HDR: la lava, el foc i la llum del sol brillen més.",
|
||||
"How frames reach the screen while VSync is off.": "Com arriben els fotogrames a la pantalla mentre VSync està desactivat.",
|
||||
"Efficient sleeps until the next frame; Precise spins, like vanilla.": "Dors eficients fins al següent fotograma; Girades precises, com la vainilla.",
|
||||
"Fills the screen (borderless).": "Omple la pantalla (sense vores).",
|
||||
"Brightens dark places.": "Il·lumina els llocs foscos.",
|
||||
"Lowers the frame rate when minimised, or idle too.": "Redueix la velocitat de fotogrames quan es minimitza o també està inactiva.",
|
||||
"Sways the view while walking.": "Oblida la vista mentre camina.",
|
||||
"Fades newly loaded chunks in.": "Esvaeix els fragments que s'han carregat recentment.",
|
||||
"Darkens the screen's edges.": "Enfosqueix les vores de la pantalla.",
|
||||
"Shows when the world saves.": "Mostra quan el món salva.",
|
||||
"Shows attack cooldown.": "Mostra el temps de reutilització de l'atac.",
|
||||
"60 FPS cap (30 in menus or unfocused), half the workers: less power.": "Limit de 60 FPS (30 en menús o desenfocat), la meitat dels treballadors: menys potència.",
|
||||
"Threads that generate, light and mesh chunks. Next start.": "Fils que generen trossos lleugers i de malla. Pròxim inici.",
|
||||
"Vulkan, then DirectX 12 (Windows) or OpenGL (Linux) where it fails. Next start.": "Vulkan, després DirectX 12 (Windows) o OpenGL (Linux) on falla. Pròxim inici.",
|
||||
"Water and glass in one buffer: fewer draw calls, a bit more VRAM. Next start.": "Aigua i vidre en un sol buffer: menys trucades de dibuix, una mica més de VRAM. Pròxim inici.",
|
||||
"Mesh data sent to the GPU per frame. Lower is smoother while loading.": "Dades de malla enviades a la GPU per fotograma. La part inferior és més suau mentre es carrega.",
|
||||
"Frame rate and frame times over the game, with a graph.": "Velocitat de fotogrames i temps de fotogrames al llarg del joc, amb un gràfic.",
|
||||
"horizon.multiplayer.finding_friend": "Trobar el món del teu amic...",
|
||||
"horizon.multiplayer.not_signed_in": "Aquest servidor està en mode en línia. Inicieu la sessió amb el vostre compte de Microsoft al llançador d'Horizon per unir-vos-hi.",
|
||||
"horizon.multiplayer.invalid_address": "Adreça del servidor no vàlida: %s",
|
||||
"horizon.multiplayer.connected_friend_direct": "Connectat directament amb el teu amic...",
|
||||
"horizon.multiplayer.connected_friend_relay": "Connectat amb el teu amic a través del relé...",
|
||||
"Advanced": "Avançat",
|
||||
"Undo": "Desfer",
|
||||
"Search options": "Opcions de cerca",
|
||||
"Shortcut": "Drecera",
|
||||
"Distance": "Distància",
|
||||
"Display": "Mostra",
|
||||
"Interface": "Interfície",
|
||||
"Sky and weather": "Cel i temps",
|
||||
"Lighting and entities": "Il·luminació i entitats",
|
||||
"Image": "Imatge",
|
||||
"Chunk loading": "Càrrega de trossos",
|
||||
"Power": "Poder",
|
||||
"Frames": "Marcs",
|
||||
"Overlay": "Superposició",
|
||||
"Output": "Sortida",
|
||||
"Brightness": "Brillantor",
|
||||
"How far you see, the window and the HUD.": "Fins on veus, la finestra i l'HUD.",
|
||||
"The sky and weather, lighting, textures and the image.": "El cel i el temps, la il·luminació, les textures i la imatge.",
|
||||
"Chunk loading, culling and power use.": "Càrrega de trossos, eliminació i ús d'energia.",
|
||||
"How frames reach the screen, and the performance overlay.": "Com arriben els fotogrames a la pantalla i la superposició de rendiment.",
|
||||
"Brighter-than-white output on an HDR display.": "Sortida més brillant que el blanc en una pantalla HDR.",
|
||||
"Results for \"%s\"": "Resultats per a \"%s\"",
|
||||
"No settings match.": "No coincideix cap configuració.",
|
||||
"horizon.title.not_affiliated": "No està afiliat a Mojang o Microsoft",
|
||||
"horizon.extras.header.lighting": "Il·luminació",
|
||||
"horizon.extras.header.third_person": "Tercera persona",
|
||||
"horizon.extras.header.particles": "Partícules",
|
||||
"horizon.extras.header.inventory": "Inventari",
|
||||
"horizon.extras.header.chat": "Xatejar",
|
||||
"horizon.extras.header.multiplayer": "Multijugador",
|
||||
"horizon.extras.header.sound": "So",
|
||||
"horizon.extras.header.menus": "Menús",
|
||||
"horizon.extras.fullbright": "Lluminós total",
|
||||
"horizon.extras.dynamic_lights": "Llums dinàmics",
|
||||
"horizon.extras.own_name_tag": "Etiqueta de nom pròpia",
|
||||
"horizon.extras.hide_block_particles": "Amaga les partícules de trencament de blocs",
|
||||
"horizon.extras.auto_reconnect": "Reconnexió automàtica",
|
||||
"horizon.extras.ui_sound_reserve": "Conserva els canals per als sons de la IU",
|
||||
"horizon.extras.music_page": "Pàgina de música",
|
||||
"horizon.extras.mouse_tweaks": "Controls de retocs del ratolí",
|
||||
"horizon.extras.mouse_tweaks_wheel": "La roda de desplaçament mou els elements",
|
||||
"horizon.extras.sort": "Botons d'ordenació",
|
||||
"horizon.extras.sort_key": "Clau d'ordenació",
|
||||
"horizon.extras.no_ai": "Sense IA",
|
||||
"horizon.extras.agent_control": "Control d'agents",
|
||||
"horizon.extras.discord_presence": "Presència enriquida de Discord",
|
||||
"horizon.extras.splitscreen": "Pantalla dividida",
|
||||
"horizon.extras.chat_animation": "Xat suau",
|
||||
"horizon.extras.chat_indicator": "Indicador de missatge",
|
||||
"horizon.extras.wheel_cycles_settings": "La roda de desplaçament canvia la configuració",
|
||||
"horizon.extras.pack_browser": "Navegador de paquets de recursos",
|
||||
"horizon.extras.fullbright.tooltip": "Mostra blocs i entitats a plena llum, fins i tot en zones fosques.",
|
||||
"horizon.extras.dynamic_lights.tooltip": "Les torxes i altres fonts de llum agafades, caigudes o al foc il·luminen els blocs que els envolten.",
|
||||
"horizon.extras.own_name_tag.tooltip": "Mostra el teu nom a sobre del teu cap en tercera persona, tal com ho veuen els altres jugadors. S'amaga quan el servidor amaga els noms del teu equip o ets invisible.",
|
||||
"horizon.extras.hide_block_particles.tooltip": "Amaga les partícules de deixalles que esclaten d'un bloc trencat i s'esmicolen del que mines. Altres partícules es queden.",
|
||||
"horizon.extras.auto_reconnect.tooltip": "Torna a unir-se a un servidor després d'una connexió perduda o un reinici, mai després d'una expulsió o prohibició.",
|
||||
"horizon.extras.ui_sound_reserve.tooltip": "Els sons del món deixen lliures 16 dels 247 canals de so, de manera que una inundació d'ells (una gran explosió) no pot silenciar els clics del menú.",
|
||||
"horizon.extras.music_page.tooltip": "Music & Sounds obté una pàgina Música...: reprodueix ara qualsevol pista integrada o desactiva-ne una perquè el joc deixi de triar-la. No canvia res fins que desactives una pista.",
|
||||
"horizon.extras.mouse_tweaks.tooltip": "Arrossegueu amb la dreta en col·loqueu un per ranura, l'arrossegar amb l'esquerra recull l'element retingut, Maj + arrossegueu amb l'esquerra mou cada ranura.",
|
||||
"horizon.extras.mouse_tweaks_wheel.tooltip": "Avall envia un element de la ranura a l'altre costat, cap amunt en torna un.",
|
||||
"horizon.extras.sort.tooltip": "Ordena l'inventari, els cofres, els barrils, els cofres ender i les caixes shulker en ordre de pestanyes creatives, fusionant les piles.",
|
||||
"horizon.extras.sort_key.tooltip": "Ordena la part sota el cursor. Feu clic i, a continuació, premeu una tecla; La fugida ho deslliga.",
|
||||
"horizon.extras.no_ai.tooltip": "Amaga i desactiva totes les funcions d'IA: control d'agents, horizon-ctl i servidors MCP. L'interruptor del llançador també.",
|
||||
"horizon.extras.agent_control.tooltip": "El vostre propi agent d'IA pot jugar a aquest joc mitjançant horizon-ctl o un client MCP, només en aquest ordinador.",
|
||||
"horizon.extras.discord_presence.tooltip": "Mostra Playing Horizon al teu perfil de Discord mentre s'executa Discord: menús, un jugador o multijugador, la dimensió i el temps jugat. Mai el nom d'un món ni l'adreça d'un servidor.",
|
||||
"Calibrate...": "Calibrar...",
|
||||
"Calibrate Anyway...": "Calibra de totes maneres...",
|
||||
"Use Automatic Setup": "Utilitzeu la configuració automàtica",
|
||||
"Shortcut: %s": "Drecera: %s",
|
||||
"Next": "A continuació",
|
||||
"HDR Calibration %s/%s: %s": "Calibració HDR %s/%s: %s",
|
||||
"Sets the three below full screen, one test picture at a time.": "Estableix les tres imatges de sota de pantalla completa, una imatge de prova a la vegada.",
|
||||
"A key that opens this screen from the game. Not bound at first.": "Una clau que obre aquesta pantalla des del joc. No lligat al principi.",
|
||||
"Your display didn't say how bright it gets: calibrate to set it up.": "La pantalla no va dir la brillantor que té: calibra per configurar-la.",
|
||||
"Already set up for your display. Only calibrate if HDR looks wrong.": "Ja està configurat per a la vostra pantalla. Calibreu només si l'HDR sembla incorrecte.",
|
||||
"Puts Peak Brightness and Paper White back to your display's setup.": "Torna a posar la brillantor màxima i el blanc del paper a la configuració de la pantalla.",
|
||||
"Set up for your display. Leave on Auto unless it looks wrong.": "Configureu-vos per a la vostra pantalla. Deixeu-lo en Auto tret que sembli malament.",
|
||||
"Lower it until the logo just disappears into the black.": "Baixeu-lo fins que el logotip només desaparegui al negre.",
|
||||
"Raise it until the logo just disappears into the bright square.": "Aixequeu-lo fins que el logotip desaparegui al quadrat brillant.",
|
||||
"Make the card a white that's comfortable to look at for a long time, in the light you play in.": "Feu que la targeta sigui blanca que sigui còmode de mirar durant molt de temps, a la llum on jugueu.",
|
||||
"horizon.splitscreen.profiles.forget": "Oblida't",
|
||||
"horizon.splitscreen.profiles.create": "Crear",
|
||||
"horizon.splitscreen.profiles.you": " - tu",
|
||||
"horizon.splitscreen.profiles.forget_named": "oblida %s",
|
||||
"horizon.splitscreen.profiles.previous": "Anterior",
|
||||
"horizon.splitscreen.profiles.next": "A continuació",
|
||||
"horizon.splitscreen.profiles.new_button": "Perfil nou...",
|
||||
"horizon.splitscreen.profiles.forget_title": "Heu oblidat el perfil?",
|
||||
"horizon.splitscreen.profiles.forget_leaves": "Surt de la llista d'aquesta instància.",
|
||||
"horizon.splitscreen.profiles.forget_kept": "El progrés mundial i la configuració es mantenen.",
|
||||
"horizon.splitscreen.profiles.new_title": "Nou perfil",
|
||||
"horizon.splitscreen.profiles.name_hint": "Nom (de 3 a 16 lletres, dígits, _)",
|
||||
"horizon.splitscreen.profiles.switch_title": "Canvia de perfil",
|
||||
"horizon.splitscreen.profiles.offline_note": "Els perfils fora de línia pertanyen a aquesta instància",
|
||||
"horizon.splitscreen.profiles.move": "Mou-te on jugues",
|
||||
"horizon.splitscreen.profiles.move_place": "Mou on jugues: %s",
|
||||
"horizon.friends.title": "Juga amb els amics",
|
||||
"horizon.friends.hint": "Els amics enganxen el codi després del botó Amics de la pantalla del títol, a la connexió directa o a la pàgina de reproducció del llançador.",
|
||||
"horizon.friends.copied": "Copiat",
|
||||
"horizon.friends.copy_code": "Copia el codi",
|
||||
"horizon.friends.stop_sharing": "Deixa de compartir",
|
||||
"horizon.friends.none_yet": "Encara no hi ha amics.",
|
||||
"horizon.friends.here_now": "Aquí ara: %s",
|
||||
"horizon.friends.share_intro": "Comparteix aquest món darrere d'un codi d'invitació: s'obre a LAN i els amics d'Internet s'uneixen amb el codi. Cap servidor nostre està implicat.",
|
||||
"horizon.friends.start_sharing": "Comenceu a compartir",
|
||||
"horizon.friends.troubleshooting": "Resolució de problemes...",
|
||||
"horizon.friends.stopped": "S'ha deixat de compartir el codi d'invitació.",
|
||||
"horizon.friends.short_code_changed": "Algú va seguir provant un codi curt equivocat, així que va canviar.",
|
||||
"horizon.friends.wrong_code": "Algú ha provat un codi incorrecte.",
|
||||
"horizon.friends.code_ready": "El teu codi d'invitació està preparat: Menú de joc, Juga amb els amics. Copia'l i envia'l als teus amics.",
|
||||
"horizon.friends.share_failed": "No s'ha pogut compartir el món: %s",
|
||||
"horizon.friends.finding_route": "Trobar com els amics et poden arribar...",
|
||||
"horizon.osk.shift": "Canvi",
|
||||
"horizon.osk.space": "Espai",
|
||||
"horizon.osk.delete": "Suprimeix",
|
||||
"horizon.osk.type": "Tipus",
|
||||
"horizon.osk.symbols": "Símbols",
|
||||
"horizon.osk.close": "Tancar",
|
||||
"horizon.extras.chat_animation.tooltip": "Una nova línia de xat es desplaça des de l'esquerra mentre s'esvaeix, en lloc de semblar sencera.",
|
||||
"horizon.extras.chat_indicator.tooltip": "La barra de colors a l'esquerra d'una línia de xat.",
|
||||
"horizon.extras.wheel_cycles_settings.tooltip": "La roda de desplaçament sobre un botó a la configuració canvia el seu valor, com a la vainilla. Desactivada, la roda només desplaça la llista.",
|
||||
"horizon.extras.pack_browser.tooltip": "Select Resource Packs obté un botó Afegeix que cerca Modrinth i instal·la un paquet a la carpeta de paquets. Desactivat, el joc mai contacta amb Modrinth.",
|
||||
"horizon.extras.splitscreen.tooltip": "En un món, un altre controlador pot unir-se com a jugador nou: premeu A quan ho demani, després trieu un perfil i on jugar.",
|
||||
"horizon.splitscreen.setup.monitor_unknown": "un monitor",
|
||||
"horizon.splitscreen.setup.window": "Finestra %s",
|
||||
"horizon.splitscreen.setup.new_window": "Finestra nova",
|
||||
"horizon.splitscreen.setup.fill_monitor": "Ompliu %s",
|
||||
"horizon.splitscreen.setup.done": "Fet",
|
||||
"horizon.splitscreen.setup.on": "Encès",
|
||||
"horizon.splitscreen.setup.off": "Apagat",
|
||||
"horizon.splitscreen.setup.player": "Jugador %s",
|
||||
"horizon.splitscreen.setup.revert": "Revertir",
|
||||
"horizon.splitscreen.setup.apply": "Aplicar",
|
||||
"horizon.splitscreen.setup.warning.empty_main": "Ningú juga a la finestra 1: s'amaga",
|
||||
"horizon.splitscreen.setup.warning.empty_close": "Ningú juga a la finestra %s: es tanca en Aplicar",
|
||||
"horizon.splitscreen.setup.warning.empty_new": "Ningú juga a la finestra %s: no s'obrirà",
|
||||
"horizon.splitscreen.setup.warning.on_main": "La finestra %s omple el monitor de la finestra 1: els seus jugadors juguen a la finestra 1",
|
||||
"horizon.splitscreen.setup.warning.unplugged": "El monitor de la finestra %s no està connectat: els seus jugadors juguen a la finestra 1",
|
||||
"horizon.splitscreen.setup.status.off": "La pantalla dividida està apagada.",
|
||||
"horizon.splitscreen.setup.status.enable_hint": "Enceneu-lo i, a continuació, premeu un botó d'un altre controlador d'un món.",
|
||||
"horizon.splitscreen.setup.status.join_hint": "Premeu A per unir-vos i triar un perfil.",
|
||||
"horizon.splitscreen.setup.status.idle": "Pantalla dividida inactiva",
|
||||
"horizon.splitscreen.setup.status.alone": "No hi ha altres jugadors locals.",
|
||||
"horizon.splitscreen.setup.status.solo_controls": "Els controls individuals i la retroalimentació del controlador no canvien.",
|
||||
"horizon.splitscreen.setup.window_empty": "Finestra %s: buida",
|
||||
"horizon.splitscreen.setup.note.select": "Feu clic a un reproductor o arrossegueu-lo a una finestra o un monitor.",
|
||||
"horizon.splitscreen.setup.note.apply": "Aplica per jugar d'aquesta manera, torna a desfer.",
|
||||
"horizon.splitscreen.setup.note.place": "On hauria de jugar %s?",
|
||||
"horizon.splitscreen.setup.this_player": "aquest jugador",
|
||||
"horizon.splitscreen.setup.switch_disabled": "La pantalla dividida s'apaga quan els altres han marxat (el seu menú de pausa).",
|
||||
"horizon.splitscreen.setup.window_place": "Finestra %s (%s de %s)",
|
||||
"horizon.splitscreen.setup.names": "Noms",
|
||||
"horizon.splitscreen.setup.identify": "Identificar",
|
||||
"horizon.splitscreen.setup.layout.two": "2 compartint: %s",
|
||||
"horizon.splitscreen.setup.layout.three": "3 compartint: %s",
|
||||
"horizon.splitscreen.setup.layout.two.0": "Automàtic",
|
||||
"horizon.splitscreen.setup.layout.two.1": "Colze a colze",
|
||||
"horizon.splitscreen.setup.layout.two.2": "A dalt i a baix",
|
||||
"horizon.splitscreen.setup.layout.three.0": "Un d'ample al damunt",
|
||||
"horizon.splitscreen.setup.layout.three.1": "Un alt a l'esquerra",
|
||||
"horizon.splitscreen.setup.layout.three.2": "Colze a colze",
|
||||
"horizon.splitscreen.setup.help.player": "Feu clic o arrossegueu %s per moure'ls.",
|
||||
"horizon.splitscreen.setup.help.layout_auto": "%s (al costat de l'altre quan la finestra és ampla). Premeu per canviar.",
|
||||
"horizon.splitscreen.setup.help.layout": "%s. Premeu per canviar.",
|
||||
"horizon.splitscreen.setup.help.switch": "Pantalla dividida per a aquest ordinador, encès o apagat.",
|
||||
"horizon.splitscreen.setup.help.identify": "La vista de cada jugador mostra en quina finestra es troba.",
|
||||
"horizon.splitscreen.setup.help.names": "El nom de cada jugador a la cantonada de la seva vista.",
|
||||
"horizon.splitscreen.setup.help.revert": "Desfer els canvis encara no aplicats.",
|
||||
"horizon.splitscreen.setup.help.apply": "Juga com mostra el mapa.",
|
||||
"horizon.splitscreen.setup.help.unchanged": "Encara no ha canviat res.",
|
||||
"horizon.splitscreen.setup.give_up_pad": "Renunciar Pad",
|
||||
"horizon.splitscreen.prompt.controller_connected": "Controlador connectat",
|
||||
"horizon.splitscreen.prompt.controller_disconnected": "Controlador desconnectat",
|
||||
"horizon.splitscreen.prompt.controller_disconnected.hint": "Torneu-lo a connectar o premeu un botó d'un altre",
|
||||
"horizon.splitscreen.prompt.join.one": "%s vol unir-se",
|
||||
"horizon.splitscreen.prompt.join.many": "%s els controladors volen unir-se",
|
||||
"horizon.splitscreen.prompt.join.yes": "Uneix-te",
|
||||
"horizon.splitscreen.prompt.join.as_p1": "Juga com a P1",
|
||||
"horizon.splitscreen.prompt.lost": "%s: controlador desconnectat",
|
||||
"horizon.splitscreen.prompt.lost.use_another": "Fes servir un altre",
|
||||
"horizon.splitscreen.prompt.lost.leave": "marxar",
|
||||
"horizon.splitscreen.setup.help.give_up_pad": "El vostre controlador deixa de conduir-vos i se li ofereix unir-se (A).",
|
||||
"horizon.splitscreen.setup.note.held_at": "%s a %s: A la deixa caure aquí, la B la torna a posar.",
|
||||
"horizon.splitscreen.setup.note.held": "%s agafat: esquerra/dreta escull on, A cau, B el torna a posar.",
|
||||
"Hides models behind opaque blocks. Async checks off-thread; entities tick.": "Amaga models darrere de blocs opacs. Async comprova fora de fil; les entitats marquen.",
|
||||
"Block Entities": "Bloquejar entitats",
|
||||
"Shulker Boxes": "Caixes Shulker",
|
||||
"Reuses settled boxes; lid movement stays animated.": "Reutilitza caixes assentades; el moviment de la tapa es manté animat.",
|
||||
"Signs": "Signes",
|
||||
"Reuses sign text until text, light, or font changes.": "Reutilitza el text del signe fins que canviï el text, la llum o la font.",
|
||||
"Decorated Pots": "Olles decorades",
|
||||
"Reuses still pots; break wobble and sherd changes redraw.": "Reutilitza olles encara; trencar l'oscil·lació i els canvis de fragments tornar a dibuixar.",
|
||||
"Bells": "Campanes",
|
||||
"Reuses still bells; ringing stays animated.": "Reutilitza campanes encara; el timbre es manté animat.",
|
||||
"Chests": "Cofres",
|
||||
"Reuses closed chests; moving lids stay animated.": "Reutilitza cofres tancats; les parpelles en moviment es mantenen animades.",
|
||||
"Banners": "Pancartes",
|
||||
"Reuses poles; flags and pattern layers still update.": "Reutilitza pals; les banderes i les capes de patrons encara s'actualitzen.",
|
||||
"Copper Golem Statues": "Estàtues de Golem de coure",
|
||||
"Reuses statue geometry until its block state changes.": "Reutilitza la geometria de l'estàtua fins que el seu estat de bloc canvia.",
|
||||
"Leaf Culling": "Talla de fulles",
|
||||
"Every leaf face. Vanilla's fancy leaves.": "Cada cara de fulla. Fulles elegants de vainilla.",
|
||||
"Distant Plant Dither": "Dither de planta llunyana",
|
||||
"Keeps fine plants in high-res packs from fading far away.": "Evita que les plantes fines en paquets d'alta resolució s'esvaeixin lluny.",
|
||||
"Screenshot Quality": "Qualitat de la captura de pantalla",
|
||||
"F2 screenshots at this many times the game's resolution. Higher takes longer.": "Captures de pantalla F2 amb moltes vegades la resolució del joc. Més alt triga més.",
|
||||
"Frame Generation": "Generació de fotogrames",
|
||||
"Shows a made-up frame between each two real ones: smoother, a little more lag.": "Mostra un marc inventat entre cadascun dels dos reals: més suau, una mica més de retard.",
|
||||
"Reuses the pack shadow map when sun, view and world match. Off by default.": "Reutilitza el mapa d'ombres del paquet quan el sol, la vista i el món coincideixen. Desactivat per defecte.",
|
||||
"Find BlueMap": "Busca BlueMap",
|
||||
"On servers, finds their BlueMap web map for far terrain. Next join.": "Als servidors, troba el seu mapa web BlueMap per a terrenys llunyans. A continuació uneix-te.",
|
||||
"BlueMap Radius": "Radi BlueMap",
|
||||
"How far around you BlueMap tiles are downloaded. Next join.": "A quina distància al teu voltant es descarreguen les fitxes de BlueMap. A continuació uneix-te.",
|
||||
"Synchronous": "Sincrònic",
|
||||
"Asynchronous": "Asíncron",
|
||||
"Solid": "Sòlid",
|
||||
"Solid Aggressive": "Sòlid Agressiu",
|
||||
"Hollow": "Buit",
|
||||
"Leaves fully inside a canopy draw solid: fewer see-through layers.": "Les fulles completament dins d'un dosser dibuixen sòlids: menys capes transparents.",
|
||||
"Leaves with one open side draw solid too: faster, chunkier edges.": "Les fulles amb un costat obert també dibuixen sòlids: vores més ràpides i gruixudes.",
|
||||
"Drops faces between leaves: faster, but gaps look through.": "Deixa caure cares entre les fulles: més ràpid, però els buits es veuen a través.",
|
||||
"Hotbar: Previous Slot": "Barra activa: ranura anterior",
|
||||
"Hotbar: Next Slot": "Hotbar: següent ranura",
|
||||
"horizon.agent.connected.one": "Connectat: 1 connexió d'agent",
|
||||
"horizon.agent.connected.many": "Connectat: %s connexions d'agent",
|
||||
"horizon.agent.connected.one_ago": "Connectat: 1 connexió d'agent, darrera ordre fa %s s",
|
||||
"horizon.agent.connected.many_ago": "Connectat: %s connexions d'agent, darrera ordre fa %s s",
|
||||
"horizon.agent.waiting": "Esperant un agent.",
|
||||
"horizon.agent.off": "Desactivat: els agents no poden accedir a aquest joc.",
|
||||
"horizon.agent.session_opened": "Obert per a aquesta sessió pel programa que va iniciar el joc.",
|
||||
"horizon.agent.socket": "Socket: %s (copieu els detalls del camí complet)",
|
||||
"horizon.agent.local_only": "Només local: agents en aquest ordinador, mai la xarxa.",
|
||||
"Auto (%s nits)": "Automàtic (%s nits)",
|
||||
"Hides models behind opaque blocks. Entities update. Off with custom packs.": "Amaga models darrere de blocs opacs. Actualització d'entitats. Apaga amb paquets personalitzats.",
|
||||
"horizon.extras.repro_keys": "Dreceres de gravació",
|
||||
"horizon.extras.repro_keys.tooltip": "F3+R inicia o atura un enregistrament de reproducció i F3+E escriu el seu paquet. Desactivat per defecte: una gravació copia el món.",
|
||||
"horizon.agent.record_session": "Inicieu la sessió de gravació",
|
||||
"horizon.agent.record_stop": "Atura la sessió de gravació",
|
||||
"horizon.agent.export_repro": "Exporta el paquet Repro",
|
||||
"horizon.repro.started": "La gravació va començar; F3+R l'atura i escriu el paquet.",
|
||||
"horizon.repro.stopped": "Enregistrament aturat: %s",
|
||||
"horizon.repro.bundle": "Paquet de reproducció: %s",
|
||||
"horizon.repro.error": "Reproducció: %s",
|
||||
"horizon.repro.no_recording": "Encara no hi ha cap gravació per exportar.",
|
||||
"horizon.repro.replay_started": "La reproducció ha començat: %s",
|
||||
"horizon.pack.addInfo": "Afegiu un paquet de recursos de Modrinth",
|
||||
"horizon.pack.addWorking": "Preguntant a Modrinth...",
|
||||
"horizon.pack.addNone": "No s'han trobat paquets de recursos",
|
||||
"horizon.pack.addTitle": "Afegiu un paquet de recursos",
|
||||
"horizon.pack.install": "Instal·lar",
|
||||
"horizon.pack.installing": "Instal·lació",
|
||||
"horizon.pack.installed": "Instal·lat",
|
||||
"horizon.pack.search": "Cerca",
|
||||
"horizon.pack.searchHint": "Cerca en Modrinth...",
|
||||
"horizon.pack.filters": "Filtres",
|
||||
"horizon.pack.filter.realistic": "Realista",
|
||||
"horizon.pack.filter.simplistic": "Simplista",
|
||||
"horizon.pack.filter.vanillaLike": "semblant a la vainilla",
|
||||
"horizon.pack.addFailed": "No s'ha pogut afegir el paquet: %s",
|
||||
"horizon.extras.header.cosmetics": "Cosmètics",
|
||||
"horizon.extras.cosmetics_mine": "Els meus cosmètics",
|
||||
"horizon.extras.cosmetics_mine.tooltip": "Ocult: tots els jugadors d'Horizon et veuen sense els teus cosmètics, tu inclòs. El mateix interruptor que l'armari del llançador.",
|
||||
"horizon.extras.cosmetics_others": "Cosmètica d'altres jugadors",
|
||||
"horizon.extras.cosmetics_others.tooltip": "Què porten altres jugadors d'Horizon: tot, només els seus estils d'etiquetes de nom o res. Amagat, el joc mai pregunta què porten.",
|
||||
"horizon.extras.cosmetics_auras": "Les aures i els camins dels altres",
|
||||
"horizon.extras.cosmetics_auras.tooltip": "Aures i rastres que porten altres jugadors. Desactivat per defecte.",
|
||||
"horizon.extras.cosmetics.shown": "Es mostra",
|
||||
"horizon.extras.cosmetics.hidden": "Ocult",
|
||||
"horizon.extras.cosmetics.name_tags": "Només etiquetes de nom"
|
||||
}
|
||||
@@ -10,13 +10,10 @@
|
||||
"horizon.options.move_deadzone": "Mrtvá zóna pohybu",
|
||||
"horizon.options.look_deadzone": "Mrtvá zóna pohledu",
|
||||
"horizon.options.button_glyphs": "Glyfy tlačítek",
|
||||
"horizon.options.menu_navigation": "Navigace v menu",
|
||||
"horizon.options.on_screen_keyboard": "Klávesnice na obrazovce",
|
||||
"horizon.options.chat_delay": "Zpoždění chatu",
|
||||
"horizon.options.lightbar.health": "Zdraví",
|
||||
"horizon.options.lightbar.dimension": "Dimenze",
|
||||
"horizon.options.menu_focus": "Zaměřte se",
|
||||
"horizon.options.menu_pointer": "Ukazatel",
|
||||
"horizon.options.keyboard.horizon": "Horizont",
|
||||
"horizon.options.keyboard.steam": "Pára",
|
||||
"horizon.options.unavailable": "Tato funkce zatím není v Horizon k dispozici.",
|
||||
|
||||
@@ -0,0 +1,492 @@
|
||||
{
|
||||
"horizon.options.controller": "Контроллер",
|
||||
"horizon.options.three_d_skin_layers": "3D скин сийӗсем",
|
||||
"horizon.options.vibration": "Вибраци",
|
||||
"horizon.options.adaptive_triggers": "Адаптивлӑ триггерсем",
|
||||
"horizon.options.lightbar": "Ҫутӑ йӗрӗ",
|
||||
"horizon.options.look_sensitivity": "Пӑхӑвӑн сисӗмлӗхӗ",
|
||||
"horizon.options.invert_x": "Пӑхӑвӑн X инверсийӗ",
|
||||
"horizon.options.invert_y": "Пӑхӑвӑн Y инверсийӗ",
|
||||
"horizon.options.sneak_button": "Йӑпшӑнмалли кнопка",
|
||||
"horizon.options.move_deadzone": "Куҫӑмӑн вилӗ зони",
|
||||
"horizon.options.look_deadzone": "Пӑхӑвӑн вилӗ зони",
|
||||
"horizon.options.button_glyphs": "Кнопка глифӗсем",
|
||||
"horizon.options.on_screen_keyboard": "Экран ҫинчи клавиатура",
|
||||
"horizon.options.chat_delay": "Чат кая юлни",
|
||||
"horizon.options.lightbar.health": "Сывлӑх",
|
||||
"horizon.options.lightbar.dimension": "Виҫе",
|
||||
"horizon.options.glyphs.auto": "Авто",
|
||||
"horizon.options.keyboard.auto": "Авто",
|
||||
"horizon.options.unavailable": "Ку функци Horizon-ра хальлӗхе ҫук-ха.",
|
||||
"horizon.options.search": "Шырав настройкисем...",
|
||||
"horizon.pages.mods": "Модсем",
|
||||
"horizon.pages.shader_packs": "Шейдер пакетӗсем",
|
||||
"horizon.pages.shader_options": "Шейдер опцийӗсем",
|
||||
"horizon.pages.controller": "Контроллер настройкисем",
|
||||
"horizon.pages.controller_binds": "Контроллер ҫыхӑнтарать",
|
||||
"horizon.pages.extras": "Horizon Хушма",
|
||||
"horizon.pages.settings": "Horizon Настройки",
|
||||
"horizon.pages.agent": "ИИ агенчӗ",
|
||||
"horizon.split.leave": "Тухса кай",
|
||||
"horizon.pages.split_settings": "Сплитскрин настройкисем",
|
||||
"horizon.pages.split_profiles": "Кам вылять?",
|
||||
"horizon.pages.split_setup": "Сплит-скрин настройки",
|
||||
"horizon.pages.music": "Музыка",
|
||||
"horizon.pages.music.menu": "Меню",
|
||||
"horizon.pages.music.overworld": "Ҫӳлти тӗнче",
|
||||
"horizon.pages.music.creative": "Пултарулӑх",
|
||||
"horizon.pages.music.underwater": "Шыв айӗнче",
|
||||
"horizon.pages.music.end": "Вӗҫӗ",
|
||||
"horizon.pages.music.boss": "Пуҫлӑх",
|
||||
"horizon.pages.music.credits": "Кредитсем",
|
||||
"horizon.pages.music.overworld_biomes": "Тӗнче ҫийӗнчи биомсем",
|
||||
"horizon.pages.music.nether_biomes": "Ҫӗр айӗнчи биомсем",
|
||||
"horizon.pages.music.end_biomes": "Вӗҫлӗ биомсем",
|
||||
"horizon.pages.music.other": "Ытти музыка",
|
||||
"horizon.pages.music.empty": "Музыка йӗрӗсем ҫук: вӑйӑ сассисем ҫӗкленмеҫҫӗ.",
|
||||
"horizon.pages.music.tooltip": "Вӑрттӑн трексем, лару-тӑру тӑрӑх: халех пӗрне выляса пӑхӑр е хӑшне те пулин сӳнтерӗр, вара вӑйӑ ӑна суйласа илме чарӑнӗ.",
|
||||
"horizon.pages.settings.tooltip": "Horizon хӑйӗн настройкисем: графика, контроллерсем, экстрасем тата модсем.",
|
||||
"horizon.pages.graphics.tooltip": "Графика, ансат: кашни настройка мӗн хак тӑнине калать.",
|
||||
"horizon.pages.graphics_advanced.tooltip": "Кашни графика настройки, Horizon кӗнӗ, кашни хакӗ мӗн чухлӗ.",
|
||||
"horizon.pages.controller.tooltip": "Контроллерсем: вӗсен кнопкисем, патаккисем, вибраци тата меню навигацийӗ.",
|
||||
"horizon.pages.extras.tooltip": "Опционаллӑ хушӑмсем, пурте стандартлӑ майпа: вӑйӑ ваниль пек юлать, эсир ӑна ҫутиччен.",
|
||||
"horizon.pages.agent.tooltip": "Хӑвӑрӑн AI агентне ҫак компьютер ҫинче horizon-ctl тата MCP клиентсемпе выляма ирӗк парӑр.",
|
||||
"horizon.pages.split_profiles.tooltip": "Кам вылять: ҫак вӑйӑ папкинче упранакан профиль.",
|
||||
"horizon.pages.split_setup.tooltip": "Чӳречесемпе мониторсем, кам ӑҫта выляни.",
|
||||
"horizon.pages.shader_packs.tooltip": "Шейдер пакетӗсем шейдер пакетӗсенчен: Horizon хӑйӗн тата шейдерсен/ форматӗнчисем. Пӗрре чупать.",
|
||||
"horizon.pages.mods.tooltip": "Horizon валли тунӑ модсем, horizon-mods папкинчен. Кашниех хӑйӑр ещӗкӗнче ӗҫлет те ӑна ҫутиччен сӳнсе тӑрать.",
|
||||
"horizon.pages.open.graphics": "Графика...",
|
||||
"horizon.pages.open.graphics_advanced": "Анлӑ графика...",
|
||||
"horizon.pages.open.shader_packs": "Шейдер пакетӗсем...",
|
||||
"horizon.pages.open.controller": "Контроллер настройкисем...",
|
||||
"horizon.pages.open.split_setup": "Сплитскрин...",
|
||||
"horizon.pages.open.extras": "Ытлашши...",
|
||||
"horizon.pages.open.mods": "Модсем...",
|
||||
"horizon.pages.open.agent": "ИИ агенчӗ...",
|
||||
"horizon.pages.open.horizon_graphics": "Horizon Графика...",
|
||||
"horizon.pages.open.controller_binds": "Контроллер ҫыхӑнтарать...",
|
||||
"horizon.pages.open.horizon_settings": "Horizon Настройки...",
|
||||
"horizon.pages.open.music": "Музыка...",
|
||||
"horizon.mods.empty": "Модсем ҫук: .hmod файлсене horizon-mods папкине лартӑр",
|
||||
"horizon.mods.stopped": " (Чарӑннӑ)",
|
||||
"horizon.mods.not_built": " (Туман)",
|
||||
"horizon.mods.settings": "Настройкӑсем",
|
||||
"horizon.mods.in_world": " (тӗнчене улӑштарма хӑвар)",
|
||||
"horizon.mods.open_folder": "Мод папкине уҫӑр",
|
||||
"horizon.shader_packs.empty": "Шейдер пакетӗсем ҫук: вӗсене шейдер пакетӗсем папкӑна лартӑр",
|
||||
"horizon.shader_options.open": "Шейдер опцийӗсем...",
|
||||
"horizon.shader_options.profile": "Профиль",
|
||||
"horizon.shader_options.loading": "Шейдер пакетӗн опцийӗсене вулатӑп...",
|
||||
"horizon.agent.copy_details": "Ҫыхӑну даннӑйӗсене копилесе илӗр",
|
||||
"horizon.multiplayer.join": "Пӗрлешӗр",
|
||||
"horizon.multiplayer.cancel_reconnecting": "Ҫӗнӗрен ҫыхӑнассине пӑрахӑҫла",
|
||||
"horizon.multiplayer.join_friend": "Тус ҫумне хутшӑн",
|
||||
"horizon.multiplayer.invite_code": "Йыхрав кодӗ",
|
||||
"horizon.multiplayer.relay": "Реле (опционально)",
|
||||
"Preset": "Малтанах лартнӑ",
|
||||
"LOD Distance": "LOD дистанцийӗ",
|
||||
"Far Detail": "Инҫетри вак-тӗвек",
|
||||
"Cave Culling": "Ханкӑрсене пӗтерни",
|
||||
"Entity Culling": "Субъектсене пӗтересси",
|
||||
"Chunk Updates": "Ҫӗнӗлӗхсем",
|
||||
"Upload Budget": "Бюджета ярса парӑр",
|
||||
"Sky": "Тӳпе",
|
||||
"Fog": "Тӗтре",
|
||||
"Weather": "Ҫанталӑк",
|
||||
"Animated Textures": "Анимациллӗ текстурӑсем",
|
||||
"Present Mode": "Хальхи режим",
|
||||
"Frame Pacing": "Кадр темпӗ",
|
||||
"Worker Threads": "Ӗҫлекен ҫипсем",
|
||||
"Resolution Scale": "Ҫирӗплӗх шкали",
|
||||
"Anti-aliasing": "Анти-плюс",
|
||||
"Upscaling": "Ӳстересси",
|
||||
"Paper White": "Шурӑ хут",
|
||||
"Peak Brightness": "Чи пысӑк ҫутӑлӑх",
|
||||
"Black Level": "Хура ур.",
|
||||
"UI Brightness": "UI ҫутӑлӑхӗ",
|
||||
"Battery Mode": "Аккумулятор режимӗ",
|
||||
"Graphics API": "Графика API",
|
||||
"Translucent Batching": "Ҫурма ҫутӑ ҫыхӑну",
|
||||
"Performance Overlay": "Ӗҫ тухӑҫлӑхӗн ҫиелти сийӗ",
|
||||
"Full Detail Distance": "Пӗтӗмӗшле дистанци",
|
||||
"On": "Ҫ",
|
||||
"Off": "Сӳнтернӗ",
|
||||
"Unlimited": "Чикӗсӗр",
|
||||
"Auto": "Авто",
|
||||
"Custom": "Ятарлӑ",
|
||||
"Performance": "Спектакль",
|
||||
"Balanced": "Шайлашуллӑ",
|
||||
"Quality": "Пахалӑх",
|
||||
"Ultra": "Ультра",
|
||||
"Ultra Performance": "Ультра ӗҫ тухӑҫлӑхӗ",
|
||||
"Native": "Натив",
|
||||
"Full": "Тулли",
|
||||
"Reduced": "Пӗчӗклетнӗ",
|
||||
"Efficient": "Тухӑҫлӑ",
|
||||
"Precise": "Тӗрӗс",
|
||||
"Auto (VSync)": "Авто (VSync)",
|
||||
"Mailbox": "Почта ещӗкӗ",
|
||||
"Immediate": "Çийӗнчех",
|
||||
"FPS and Graph": "FPS тата график",
|
||||
"TAA": "ТАА",
|
||||
"No cost": "Тӑкак ҫук",
|
||||
"Low cost": "Йӳнӗ хак",
|
||||
"Medium cost": "Вӑтам хак",
|
||||
"High cost": "Пысӑк хак",
|
||||
"Saves time": "Вӑхӑта перекетлет",
|
||||
"Graphics": "Графика",
|
||||
"Done": "Пӗтернӗ",
|
||||
"This feature is not yet available in Horizon.": "Ку функци Horizon-ра хальлӗхе ҫук-ха.",
|
||||
"Your display or system doesn't offer HDR output.": "Сирӗн дисплей е система HDR тухӑҫне сӗнмест.",
|
||||
"Turn HDR on to use it.": "Ӑна усӑ курма HDR ҫутӑр.",
|
||||
"Your GPU or graphics API doesn't support it.": "Сирӗн GPU е графика API ӑна пулӑшмасть.",
|
||||
"%s chunks": "%s татӑкӗсем",
|
||||
"%s per frame": "%s кашни кадршӑн",
|
||||
"%s MiB/frame": "%s МиБ/кадр",
|
||||
"%s KiB/frame": "%s КиБ/кадр",
|
||||
"Auto (%s)": "Авто (%s)",
|
||||
"Full-detail terrain range. LOD Distance can extend local worlds farther.": "Пӗтӗм детальлӗ ҫӗр диапазонӗ. LOD Дистанци вырӑнти тӗнчесене тата аяккарах тӑсма пултарать.",
|
||||
"Coarse distant terrain in local worlds. Integrated GPUs stop at 128 chunks.": "Вырӑнти тӗнчери инҫетри ҫӗр лаптӑкӗ. Пӗрлештернӗ GPU-сем 128 татӑк ҫинче чарӑнаҫҫӗ.",
|
||||
"Reduced draws far terrain coarser: faster on this integrated GPU.": "Ҫак пӗрлештернӗ GPU-ра пӗчӗклетни ҫӗре чылай хытӑрах туртать: хӑвӑртрах.",
|
||||
"Reduced draws far terrain coarser, for GPUs it slows down.": "Пӗчӗклетни ҫӗре чылай хытӑрах туртать, GPU-семшӗн вӑл ерипенлетет.",
|
||||
"Field of view. Wider shows more terrain at once.": "Курӑну уйӗ. Сарлакараххи пӗр харӑсах ытларах ҫӗре кӑтартать.",
|
||||
"Caps frames per second; a cap saves power and heat.": "Ҫеккунтра кадрсене чакарать; ҫӗлӗк энергипе ӑшша перекетлет.",
|
||||
"Waits for the display's refresh: no tearing, a little latency.": "Дисплей ҫӗнелессине кӗтет: ҫурӑлмасть, кӑштах кая юлать.",
|
||||
"Size of menus and the HUD.": "Менюсен калӑпӑшӗ тата HUD.",
|
||||
"Sets the options below together. Changing one makes it Custom.": "Аялта панӑ опцисене пӗрле лартать. Пӗрне улӑштарни ӑна Custom тӑвать.",
|
||||
"Lava, fire and sunlight shine brighter than white. Needs an HDR display.": "Лава, вут-ҫулӑм тата хӗвел ҫути шурӑран ҫутӑрах ҫуталса тӑраҫҫӗ. HDR дисплей кирлӗ.",
|
||||
"Your display's darkest black. 0 for OLED; LCDs glow a little.": "Сирӗн дисплей чи тӗксӗм хура. 0 OLED валли; ЖК-дисплейсем кӑштах ҫуталаҫҫӗ.",
|
||||
"How bright highlights get. Auto: the peak your system reports.": "Мӗнле ҫутӑ ҫутӑсем пулаҫҫӗ. Авто: сирӗн системӑн пӗлтерекен пикӗ.",
|
||||
"How bright white paper and menus look. Auto: your desktop's white.": "Мӗнле ҫутӑ шурӑ хут тата менюсем курӑнаҫҫӗ. Авто: сирӗн ӗҫ сӗтелӗ шурӑ.",
|
||||
"How bright the HUD and menus are, against paper white.": "HUD тата менюсем мӗнле ҫутӑ, хут ҫинчи шурӑ тӗспе танлаштарсан.",
|
||||
"How far mobs, crops and machines keep working. CPU time.": "Мобсем, культурӑсем тата машинӑсем мӗн таран ӗҫлеҫҫӗ. Процессор вӑхӑчӗ.",
|
||||
"How far away mobs and items are drawn, as a share of normal.": "Мобсемпе япаласем мӗн чухлӗ аяккалла туртӑнаҫҫӗ, йӗркеллӗ пай пек.",
|
||||
"Skips terrain hidden behind closed sections. Off costs a lot.": "Хупӑ участоксем хыҫӗнче пытаннӑ ҫӗре сиктерсе хӑварать. Офф нумай тӑкакланать.",
|
||||
"Hides entities behind opaque blocks.": "Тӗксӗм блоксем хыҫӗнче япаласене пытарать.",
|
||||
"No entity occlusion culling.": "Объект окклюзийӗ ҫук.",
|
||||
"CPU occlusion test runs this frame.": "Ҫак кадра процессор окклюзи тӗрӗслевӗ ӗҫлеттерет.",
|
||||
"Occlusion checks run on a worker thread.": "Окклюзи тӗрӗслевӗсем ӗҫлекен ҫип ҫинче ӗҫлеҫҫӗ.",
|
||||
"Meshed sections uploaded per frame. Lower is smoother while loading.": "Кадр пуҫне ярса панӑ сетчатӑй пайсем. Аялта тиенӗ чухне тикӗсрех.",
|
||||
"Soft shadows in corners. Costs chunk building time only.": "Кӗтессенче ҫемҫе мӗлкесем. Ҫурт-йӗр тунӑ вӑхӑта ҫеҫ тӑкаклать.",
|
||||
"Smaller copies of block textures for distant terrain: less shimmer.": "Инҫетри ҫӗр ҫинчи блок текстурин пӗчӗкрех копийӗсем: йӑлтӑркка сахалрах.",
|
||||
"Blends grass and water colours across biomes when building chunks.": "Татӑксем тунӑ чухне курӑкпа шыв тӗсӗсене биомсем тӑрӑх хутӑштарать.",
|
||||
"Cloud layer: off, flat (fast) or 3D (fancy).": "Пӗлӗт сийӗ: сӳннӗ, лаптак (хӑвӑрт) е 3D (чаплӑ).",
|
||||
"How far clouds reach, in chunks.": "Пӗлӗтсем мӗн таран ҫитеҫҫӗ, татӑкӑн-татӑкӑн.",
|
||||
"Draws the sky, sun, moon and stars.": "Тÿпене, хӗвеле, уйӑха тата ҫӑлтӑрсене ÿкерет.",
|
||||
"Distance fog. Off shows the edge of the loaded world.": "Инҫетри тӗтре. Off — тиеннӗ тӗнче хӗррине кӑтартать.",
|
||||
"Draws rain and snow.": "Ҫумӑрпа юр ҫӑвать.",
|
||||
"How far rain and snow fall around you.": "Сирӗн тавра ҫумӑрпа юр мӗн чухлӗ ӳкет.",
|
||||
"How many particles effects spawn.": "Миҫе пайӑрка эффект ҫуратать.",
|
||||
"Round shadows under mobs and items.": "Ҫаврака мӗлкесем ушкӑнсемпе япаласем айӗнче.",
|
||||
"Leaves with see-through gaps. Off draws them solid.": "Ҫулҫӑсем витӗр курӑнакан хушӑксемлӗ. Офф вӗсене ҫирӗп туртать.",
|
||||
"Sorts water and glass more exactly behind each other.": "Шывпа кӗленчене пӗр-пӗрин хыҫҫӑн тӗрӗсрех уйӑрать.",
|
||||
"Which chunk rebuilds wait for the frame: none, nearby or yours.": "Хӑш татӑк ҫӗнӗрен йӗркеленет кадра кӗтет: ҫук, ҫывӑхра е санӑн.",
|
||||
"Animates water, lava, fire and other moving textures.": "Шыв, лава, вут-ҫулӑм тата ытти куҫакан япаласене чӗртсе тӑратать.",
|
||||
"World pixels per screen pixel. Below 100% is faster on the GPU.": "Экран пикселӗ пуҫне тӗнче пикселӗсем. 100% аяларах GPU ҫинче хӑвӑртрах.",
|
||||
"Smooths jagged edges. FXAA: softer. TAA: smoothest, moving things may trail.": "Шӑллӑ хӗррисене тикӗслетет. FXAA: ҫемҫерех. ТАА: чи тикӗс, куҫакан япаласем йӗрлеме пултараҫҫӗ.",
|
||||
"Renders the world smaller and rebuilds it with TAA. Faster, softer.": "Тӗнчене пӗчӗклетет те ӑна TAA-па ҫӗнӗрен тӑвать. Хӑвӑртрах, ҫемҫерех.",
|
||||
"HDR output on an HDR display: lava, fire and sunlight shine brighter.": "HDR дисплей ҫинче HDR тухӑҫӗ: лава, вут тата хӗвел ҫути ҫутӑрах ҫутатаҫҫӗ.",
|
||||
"How frames reach the screen while VSync is off.": "VSync ӗҫлемен чухне кадрсем экран ҫине мӗнле ҫитеҫҫӗ.",
|
||||
"Efficient sleeps until the next frame; Precise spins, like vanilla.": "Тепӗр кадрчченех лайӑх ҫывӑрать; Тӗрӗс ҫаврӑнусем, ваниль пек.",
|
||||
"Fills the screen (borderless).": "Экрана тултарать (чикӗсӗр).",
|
||||
"Brightens dark places.": "Тӗттӗм вырӑнсене ҫутатать.",
|
||||
"Lowers the frame rate when minimised, or idle too.": "Кадрсен хӑвӑртлӑхне пӗчӗклетнӗ чухне е ӗҫлемен чухне те чакарать.",
|
||||
"Sways the view while walking.": "Утнӑ чухне курӑнӑва суллантарать.",
|
||||
"Fades newly loaded chunks in.": "Ҫӗнӗрен ҫӗкленӗ татӑксене ҫухатать.",
|
||||
"Darkens the screen's edges.": "Экран хӗррисене тӗксӗмлетет.",
|
||||
"Shows when the world saves.": "Тӗнче хӑҫан ҫӑлӑннине кӑтартать.",
|
||||
"Shows attack cooldown.": "Атакӑна сивӗтмелли вӑхӑта кӑтартать.",
|
||||
"60 FPS cap (30 in menus or unfocused), half the workers: less power.": "60 FPS чикӗ (менюсенче 30 е фокуссӑр), ӗҫлекенсен ҫурри: хӑват сахалрах.",
|
||||
"Threads that generate, light and mesh chunks. Next start.": "Генерацилекен ҫипсем, ҫутӑ тата сетка татӑкӗсем. Тепӗр пуҫламӑш.",
|
||||
"Vulkan, then DirectX 12 (Windows) or OpenGL (Linux) where it fails. Next start.": "Vulkan, унтан DirectX 12 (Windows) е OpenGL (Linux) ӑҫта вӑл ӗҫлемест. Тепӗр пуҫламӑш.",
|
||||
"Water and glass in one buffer: fewer draw calls, a bit more VRAM. Next start.": "Шывпа кантӑк пӗр буферта: сахалрах драв чӗнӗвӗсем, кӑштах ытларах VRAM. Тепӗр пуҫламӑш.",
|
||||
"Mesh data sent to the GPU per frame. Lower is smoother while loading.": "Меш даннӑйӗсем кашни кадрта GPU-на ярса параҫҫӗ. Аялта тиенӗ чухне тикӗсрех.",
|
||||
"Frame rate and frame times over the game, with a graph.": "Вӑйӑ тӑршшӗпе кадрсен хӑвӑртлӑхӗ тата кадрсен вӑхӑчӗ, графикпа.",
|
||||
"horizon.multiplayer.finding_friend": "Юлташӑн тӗнчине тупни...",
|
||||
"horizon.multiplayer.not_signed_in": "Ку сервер онлайн режимра. Унта кӗме Horizon лаунчерта хӑвӑрӑн Microsoft аккаунтпа кӗрӗр.",
|
||||
"horizon.multiplayer.invalid_address": "Тӗрӗс мар сервер адресӗ: %s",
|
||||
"horizon.multiplayer.connected_friend_direct": "Тӳрех тусупа ҫыхӑнтӑм...",
|
||||
"horizon.multiplayer.connected_friend_relay": "Реле урлӑ тусупа ҫыхӑннӑ...",
|
||||
"General": "Пӗтӗмӗшле",
|
||||
"Advanced": "Малалла",
|
||||
"Undo": "Каялла тавӑр",
|
||||
"Search options": "Шырав опцийӗсем",
|
||||
"Shortcut": "Кӗске ҫул",
|
||||
"Distance": "Инҫет",
|
||||
"Display": "Дисплей",
|
||||
"Interface": "Интерфейс",
|
||||
"Sky and weather": "Тӳпе тата ҫанталӑк",
|
||||
"Lighting and entities": "Ҫутӑ тата япаласем",
|
||||
"Textures": "Текстурӑсем",
|
||||
"Image": "Сӑнӳкерчӗк",
|
||||
"Chunk loading": "Чунк загрузки",
|
||||
"Culling": "Кульлинг",
|
||||
"Power": "Влаҫ",
|
||||
"Frames": "Рамкӑсем",
|
||||
"Overlay": "Накладка",
|
||||
"Output": "Тухӑҫ",
|
||||
"Brightness": "Ҫутӑлӑх",
|
||||
"How far you see, the window and the HUD.": "Эсир мӗн чухлӗ куратӑр, чӳрече тата HUD.",
|
||||
"The sky and weather, lighting, textures and the image.": "Тӳпе тата ҫанталӑк, ҫутӑ, текстурӑсем тата сӑн.",
|
||||
"Chunk loading, culling and power use.": "Татӑксене тиесе ҫӗмӗресси, ҫӗмӗресси тата энергипе усӑ курасси.",
|
||||
"How frames reach the screen, and the performance overlay.": "Кадрсем экран ҫине мӗнле ҫитни тата ӗҫ тухӑҫлӑхӗн ҫиелти сийӗ.",
|
||||
"Brighter-than-white output on an HDR display.": "HDR дисплей ҫинче шурӑран ҫутӑрах тухӑҫ.",
|
||||
"Results for \"%s\"": "Результаты для \"%s\"",
|
||||
"No settings match.": "Настройкӑсем пӗр пек мар.",
|
||||
"horizon.title.not_affiliated": "Mojang е Microsoft ҫыхӑнман",
|
||||
"horizon.extras.header.lighting": "Ҫутӑ",
|
||||
"horizon.extras.header.third_person": "Виҫҫӗмӗш сӑпат",
|
||||
"horizon.extras.header.particles": "Частицӑсем",
|
||||
"horizon.extras.header.inventory": "Инвентаризаци",
|
||||
"horizon.extras.header.chat": "Чат",
|
||||
"horizon.extras.header.multiplayer": "Нумай ҫынлӑ",
|
||||
"horizon.extras.header.sound": "Сасӑ",
|
||||
"horizon.extras.header.menus": "Менюсем",
|
||||
"horizon.extras.fullbright": "Фуллбрайт",
|
||||
"horizon.extras.dynamic_lights": "Динамикӑллӑ ҫутӑсем",
|
||||
"horizon.extras.own_name_tag": "Хӑйӗн ячӗ",
|
||||
"horizon.extras.hide_block_particles": "Блок-брейк пайӑркисене пытарӑр",
|
||||
"horizon.extras.auto_reconnect": "Авто-ҫыхӑну",
|
||||
"horizon.extras.ui_sound_reserve": "UI сассисем валли каналсем упрӑр",
|
||||
"horizon.extras.music_page": "Музыка страници",
|
||||
"horizon.extras.mouse_tweaks": "Шӑши Tweaks управленийӗсем",
|
||||
"horizon.extras.mouse_tweaks_wheel": "Прокрутка урапи япаласене куҫарать",
|
||||
"horizon.extras.sort": "Сортировка кнопкисем",
|
||||
"horizon.extras.sort_key": "Сортировка уҫҫи",
|
||||
"horizon.extras.no_ai": "ИИ ҫук",
|
||||
"horizon.extras.agent_control": "Агент контролӗ",
|
||||
"horizon.extras.discord_presence": "Discord Пуян пурнӑҫ",
|
||||
"horizon.extras.splitscreen": "Сплитскрин",
|
||||
"horizon.extras.chat_animation": "Ҫемҫе калаҫу",
|
||||
"horizon.extras.chat_indicator": "Хыпар кӑтартӑвӗ",
|
||||
"horizon.extras.wheel_cycles_settings": "Прокрутка урапи настройкӑсене улӑштарать",
|
||||
"horizon.extras.pack_browser": "Ресурс пакетӗн браузерӗ",
|
||||
"horizon.extras.fullbright.tooltip": "Блоксемпе объектсене тулли ҫутӑра, тӗттӗм вырӑнсенче те кӑтартӑр.",
|
||||
"horizon.extras.dynamic_lights.tooltip": "Факелсем тата ытти ҫутӑ ҫӑлкуҫӗсем тытса тӑракан, пӑрахнӑ е ҫунакан ҫутӑ ҫӑлкуҫӗсем хӑйсен таврашӗнчи блоксене ҫутатса тӑраҫҫӗ.",
|
||||
"horizon.extras.own_name_tag.tooltip": "Ытти вылякансем курнӑ пек, сирӗн ята пуҫ тӗлӗнче виҫҫӗмӗш сӑпатра кӑтартать. Сервер сирӗн командӑн ячӗсене пытарнӑ чухне е эсир курӑнман чухне пытарнӑ.",
|
||||
"horizon.extras.hide_block_particles.tooltip": "Ҫӗмӗрӗлнӗ блокран ҫурӑлса тухнӑ ҫӳп-ҫап пайӗсене пытарать те эсир кӑларнӑ блокран ишӗлсе анать. Ытти пайӑркасем юлаҫҫӗ.",
|
||||
"horizon.extras.auto_reconnect.tooltip": "Ҫыхӑну ҫухалнӑ е ҫӗнӗрен пуҫланӑ хыҫҫӑн сервера каялла кӗрет, нихӑҫан та тапӑннӑ е чарнӑ хыҫҫӑн мар.",
|
||||
"horizon.extras.ui_sound_reserve.tooltip": "Тӗнчери сасӑсем 247 сасӑ каналӗнчен 16-шне пушӑ хӑвараҫҫӗ, ҫавӑнпа та вӗсен шывӗ (пысӑк взрыв) меню ҫине пуснине шӑплантараймасть.",
|
||||
"horizon.extras.music_page.tooltip": "Music & Sounds Music... страницӑна илет: халех кирек мӗнле вӑрттӑн трека та выляса парӑр е ӑна сӳнтерӗр, вара вӑйӑ ӑна суйласа илме пӑрахӗ. Эсир ҫула сӳнтериччен нимӗн те улшӑнмасть.",
|
||||
"horizon.extras.mouse_tweaks.tooltip": "Сылтӑм еннелле туртни кашни слота пӗрер вырнаҫтарать, сулахай еннелле туртни тытса тӑракан япалана пухать, Shift + сулахай еннелле туртни кашни слота куҫарать.",
|
||||
"horizon.extras.mouse_tweaks_wheel.tooltip": "Аялалла слотӑн пӗр япалине тепӗр еннелле ярать, ҫӳлелле пӗрне каялла илсе килет.",
|
||||
"horizon.extras.sort.tooltip": "Инвентаре, арчасене, пичкесене, вӗҫлӗ арчасене тата шулкер ещӗкӗсене творчествӑлла вкладка йӗркипе йӗркелет, стексене пӗрлештерет.",
|
||||
"horizon.extras.sort_key.tooltip": "Курсор айӗнчи пайне йӗркелет. Пусӑр, унтан клавишӑна пусӑр; Тарасси ӑна салтать.",
|
||||
"horizon.extras.no_ai.tooltip": "ИИ-н кашни функцине пытарать тата сӳнтерет: агент управленийӗ, horizon-ctl тата MCP серверӗсем. Пускачӑн переключателӗ те.",
|
||||
"horizon.extras.agent_control.tooltip": "Сирӗн хӑвӑрӑн ИИ агенчӗ ҫак вӑййа horizon-ctl е MCP клиент урлӑ ҫак компьютер ҫинче кӑна выляма пултарать.",
|
||||
"horizon.extras.discord_presence.tooltip": "Discord ӗҫленӗ вӑхӑтра сирӗн Discord профильте Horizon вылянине кӑтартать: менюсем, пӗр ҫын е нумай ҫын, виҫе тата вылянӑ вӑхӑт. Нихӑҫан та тӗнче ячӗ е сервер адресӗ.",
|
||||
"Calibrate...": "Калибровка...",
|
||||
"Calibrate Anyway...": "Ҫапах та калибровка...",
|
||||
"Use Automatic Setup": "Автоматла настройкӑпа усӑ курӑр",
|
||||
"Shortcut: %s": "Кӗске ҫул: %s",
|
||||
"Next": "Малалла",
|
||||
"HDR Calibration %s/%s: %s": "HDR калибровка %s/%s: %s",
|
||||
"Sets the three below full screen, one test picture at a time.": "Аялта виҫҫӗшне тулли экран ҫине лартать, пӗрер тӗрӗслев ӳкерчӗкӗ.",
|
||||
"A key that opens this screen from the game. Not bound at first.": "Вӑйӑран ҫак экрана уҫакан уҫҫи. Малтанах ҫыхӑнман.",
|
||||
"Your display didn't say how bright it gets: calibrate to set it up.": "Сирӗн дисплей ҫинче вӑл мӗнле ҫутӑ пулнине каламан: ӑна лартма калибровка тумалла.",
|
||||
"Already set up for your display. Only calibrate if HDR looks wrong.": "Сирӗн дисплей валли хатӗрленӗ ӗнтӗ. HDR тӗрӗс мар курӑнсан ҫеҫ калибровка тӑвӑр.",
|
||||
"Puts Peak Brightness and Paper White back to your display's setup.": "Чи пысӑк ҫутӑлӑха тата хут шуррине сирӗн дисплей настройкине каялла тавӑрать.",
|
||||
"Set up for your display. Leave on Auto unless it looks wrong.": "Хӑвӑрӑн дисплей валли настройка тӑвӑр. Авто ҫинче хӑварӑр, енчен те вӑл тӗрӗс мар пек курӑнмасть пулсан.",
|
||||
"Lower it until the logo just disappears into the black.": "Ӑна логотип хура тӗспе ҫухаличчен антарӑр.",
|
||||
"Raise it until the logo just disappears into the bright square.": "Ӑна логотип ҫутӑ тӑваткал ҫине ҫухаличченех ҫӗклесе тӑрӑр.",
|
||||
"Make the card a white that's comfortable to look at for a long time, in the light you play in.": "Карттӑна шурӑ тӗслӗ тӑвӑр, ӑна нумайччен пӑхма меллӗ пултӑр, эсир вылякан ҫутӑра.",
|
||||
"horizon.splitscreen.profiles.forget": "Манӑр",
|
||||
"horizon.splitscreen.profiles.create": "Тӑвӑр",
|
||||
"horizon.splitscreen.profiles.you": " - эсир",
|
||||
"horizon.splitscreen.profiles.forget_named": "Манӑр %s",
|
||||
"horizon.splitscreen.profiles.previous": "Унчченхи",
|
||||
"horizon.splitscreen.profiles.next": "Малалла",
|
||||
"horizon.splitscreen.profiles.new_button": "Ҫӗнӗ профиль...",
|
||||
"horizon.splitscreen.profiles.forget_title": "Профиль маннӑ-и?",
|
||||
"horizon.splitscreen.profiles.forget_leaves": "Вӑл ҫак экземплярӑн списокӗнчен тухать.",
|
||||
"horizon.splitscreen.profiles.forget_kept": "Тӗнчери прогресс тата настройкӑсем упранаҫҫӗ.",
|
||||
"horizon.splitscreen.profiles.new_title": "Ҫӗнӗ профиль",
|
||||
"horizon.splitscreen.profiles.name_hint": "Ят (3-16 сас палли, цифра, _)",
|
||||
"horizon.splitscreen.profiles.switch_title": "Профиль улӑштармалла",
|
||||
"horizon.splitscreen.profiles.offline_note": "Офлайн профильсем ҫак экземпляра кӗреҫҫӗ",
|
||||
"horizon.splitscreen.profiles.move": "Ӑҫта вылятӑн, ҫавӑнта куҫ",
|
||||
"horizon.splitscreen.profiles.move_place": "Ӑҫта вылятӑн, ҫавӑнта куҫ: %s",
|
||||
"horizon.friends.title": "Юлташсемпе выля",
|
||||
"horizon.friends.hint": "Туссем ҫак кода титул экранӗнчи Туссем кнопки хыҫҫӑн, Тӳрӗ ҫыхӑнура е пуҫлаканӑн Play страницинче ҫыпӑҫтараҫҫӗ.",
|
||||
"horizon.friends.copied": "Копиленӗ",
|
||||
"horizon.friends.copy_code": "Код копийӗ",
|
||||
"horizon.friends.stop_sharing": "Пайлама пӑрахӑр",
|
||||
"horizon.friends.none_yet": "Кунта туссем ҫук-ха.",
|
||||
"horizon.friends.here_now": "Акӑ халӗ: %s",
|
||||
"horizon.friends.share_intro": "Ҫак тӗнчене йыхрав кодӗ хыҫӗнче пайла: вӑл LAN-а уҫӑлать, интернетри туссем вара ҫав кодпа хутшӑнаҫҫӗ. Пирӗн пӗр сервер та ҫак ӗҫе хутшӑнмасть.",
|
||||
"horizon.friends.start_sharing": "Пайлама пуҫлӑр",
|
||||
"horizon.friends.troubleshooting": "Ҫитменлӗхсене пӗтересси...",
|
||||
"horizon.friends.stopped": "Чӗнӳ кодне пайлама пӑрахрӑм.",
|
||||
"horizon.friends.short_code_changed": "Такам кӗске кода йӑнӑш ҫырса пӑхрӗ, ҫавӑнпа вӑл улшӑнчӗ.",
|
||||
"horizon.friends.wrong_code": "Такам йӑнӑш кодпа усӑ курса пӑхнӑ.",
|
||||
"horizon.friends.code_ready": "Сирӗн чӗнӳ кодӗ хатӗр: Вӑйӑ меню, Туссемпе выля. Ӑна копилесе юлташсене ярса парӑр.",
|
||||
"horizon.friends.share_failed": "Тӗнчене пайлаймарӑм: %s",
|
||||
"horizon.friends.finding_route": "Юлташсем сирӗн пата мӗнле ҫитме пултарнине тупасси...",
|
||||
"horizon.osk.shift": "Смена",
|
||||
"horizon.osk.space": "Космос",
|
||||
"horizon.osk.delete": "Пӗтер",
|
||||
"horizon.osk.type": "Тип",
|
||||
"horizon.osk.symbols": "Символсем",
|
||||
"horizon.osk.close": "Хуп",
|
||||
"horizon.extras.chat_animation.tooltip": "Ҫӗнӗ чат йӗрки сулахай енчен шуса кӗрет, вӑл вара пӗтӗмӗшпех курӑнмасть.",
|
||||
"horizon.extras.chat_indicator.tooltip": "Чат йӗркин сулахай енчи тӗслӗ йӗр.",
|
||||
"horizon.extras.wheel_cycles_settings.tooltip": "Настройкӑсенчи кнопка урлӑ ҫаврӑнакан ҫаврашка унӑн хакне улӑштарать, ваниль ҫинчи пекех. Сӳнтерсен, урапа списока ҫеҫ куҫарать.",
|
||||
"horizon.extras.pack_browser.tooltip": "Ресурс пакетӗсене суйласа илсен, хушма кнопка пулать, вӑл Modrinth шырать те сирӗн пакетсен папкине пакет вырнаҫтарать. Ҫук, вӑйӑ нихҫан та Modrinth ҫыхӑнмасть.",
|
||||
"horizon.extras.splitscreen.tooltip": "Тӗнчере тепӗр контроллер ҫӗнӗ вылякан пулса хутшӑнма пултарать: вӑл ыйтсан А пусмалла, унтан профиль суйласа илмелле тата ӑҫта вылямаллине суйласа илмелле.",
|
||||
"horizon.splitscreen.setup.monitor": "Монитор %s",
|
||||
"horizon.splitscreen.setup.monitor_unknown": "монитор",
|
||||
"horizon.splitscreen.setup.window": "Чӳрече %s",
|
||||
"horizon.splitscreen.setup.new_window": "Çӗнӗ чӳрече",
|
||||
"horizon.splitscreen.setup.fill_monitor": "%s тултар",
|
||||
"horizon.splitscreen.setup.done": "Пӗтернӗ",
|
||||
"horizon.splitscreen.setup.on": "Ҫ",
|
||||
"horizon.splitscreen.setup.off": "Сӳнтернӗ",
|
||||
"horizon.splitscreen.setup.player": "Вылякан %s",
|
||||
"horizon.splitscreen.setup.revert": "Каялла тавӑр",
|
||||
"horizon.splitscreen.setup.apply": "Заявлени",
|
||||
"horizon.splitscreen.setup.warning.empty_main": "1-мӗш чӳречере никам та вылямасть: вӑл пытанать",
|
||||
"horizon.splitscreen.setup.warning.empty_close": "Window %s-ра никам та вылямасть: вӑл Apply ҫинче хупӑнать",
|
||||
"horizon.splitscreen.setup.warning.empty_new": "Window %s-ра никам та вылямасть: вӑл уҫӑлмасть",
|
||||
"horizon.splitscreen.setup.warning.on_main": "%s чӳрече 1-мӗш чӳрече мониторне тултарать: унӑн выляканӗсем 1-мӗш чӳречере выляҫҫӗ",
|
||||
"horizon.splitscreen.setup.warning.unplugged": "Window %s мониторӗ ҫыхӑнман: унӑн выляканӗсем Window 1-ре выляҫҫӗ",
|
||||
"horizon.splitscreen.setup.status.off": "Сплитскрин сӳннӗ.",
|
||||
"horizon.splitscreen.setup.status.enable_hint": "Ӑна ҫутӑр та тӗнчери тепӗр контроллер ҫинчи кнопкӑна пусӑр.",
|
||||
"horizon.splitscreen.setup.status.join_hint": "А пусса хутшӑнӑр та профиль суйласа илӗр.",
|
||||
"horizon.splitscreen.setup.status.idle": "Сплитскрин ӗҫлемест",
|
||||
"horizon.splitscreen.setup.status.alone": "Ытти вырӑнти вылякансем ҫук.",
|
||||
"horizon.splitscreen.setup.status.solo_controls": "Пӗччен управлени тата контроллер ҫыхӑнӑвӗ улшӑнман.",
|
||||
"horizon.splitscreen.setup.window_empty": "Чӳрече %s: пушӑ",
|
||||
"horizon.splitscreen.setup.note.select": "Плеер ҫине пусӑр е ӑна чӳрече е монитор ҫине сӗтӗрсе кайӑр.",
|
||||
"horizon.splitscreen.setup.note.apply": "Ҫакӑн пек выляма ыйтӑр, каялла тавӑрса каялла тавӑрӑр.",
|
||||
"horizon.splitscreen.setup.note.place": "%s ӑҫта вылямалла?",
|
||||
"horizon.splitscreen.setup.this_player": "ку вылякан",
|
||||
"horizon.splitscreen.setup.switch_disabled": "Ыттисем тухса кайсанах Splitscreen сӳнет (вӗсен пауза меню).",
|
||||
"horizon.splitscreen.setup.window_place": "Чӳрече %s (%s %s)",
|
||||
"horizon.splitscreen.setup.names": "Ятсем",
|
||||
"horizon.splitscreen.setup.identify": "Паллӑрт",
|
||||
"horizon.splitscreen.setup.layout.two": "2 пайлани: %s",
|
||||
"horizon.splitscreen.setup.layout.three": "3 пайлани: %s",
|
||||
"horizon.splitscreen.setup.layout.two.0": "Авто",
|
||||
"horizon.splitscreen.setup.layout.two.1": "Юнашар",
|
||||
"horizon.splitscreen.setup.layout.two.2": "Ҫӳлти тата аялти",
|
||||
"horizon.splitscreen.setup.layout.three.0": "Ҫӳлте пӗр сарлака",
|
||||
"horizon.splitscreen.setup.layout.three.1": "Сулахай енче пӗр ҫӳллӗ",
|
||||
"horizon.splitscreen.setup.layout.three.2": "Юнашар",
|
||||
"horizon.splitscreen.setup.help.player": "Вӗсене куҫарма %s пусмалла е сӗтӗрмелле.",
|
||||
"horizon.splitscreen.setup.help.layout_auto": "%s (чӳрече сарлака чухне юнашар). Улшӑнма пусӑр.",
|
||||
"horizon.splitscreen.setup.help.layout": "%s. Улшӑнма пусӑр.",
|
||||
"horizon.splitscreen.setup.help.switch": "Ҫак компьютер валли пайланӑ экран, ҫутӑ е сӳнтернӗ.",
|
||||
"horizon.splitscreen.setup.help.identify": "Кашни выляканӑн курӑмӗ вӑл хӑш чӳречере пулнине кӑтартать.",
|
||||
"horizon.splitscreen.setup.help.names": "Кашни выляканӑн ячӗ вӗсен курӑмӗн кӗтессинче.",
|
||||
"horizon.splitscreen.setup.help.revert": "Хальлӗхе кӗртмен улшӑнусене каялла тавӑрӑр.",
|
||||
"horizon.splitscreen.setup.help.apply": "Карттӑ ҫинче мӗнле кӑтартнӑ, ҫавӑн пек выля.",
|
||||
"horizon.splitscreen.setup.help.unchanged": "Нимӗн те улшӑнман-ха.",
|
||||
"horizon.splitscreen.prompt.controller_connected": "Контроллер ҫыхӑннӑ",
|
||||
"horizon.splitscreen.prompt.controller_disconnected": "Контроллер татӑлнӑ",
|
||||
"horizon.splitscreen.prompt.controller_disconnected.hint": "Ӑна тепӗр хут ҫыхӑнтарӑр е тепӗр кнопкӑна пусӑр",
|
||||
"horizon.splitscreen.prompt.join.one": "%s хутшӑнасшӑн",
|
||||
"horizon.splitscreen.prompt.join.many": "%s контроллерсем хутшӑнасшӑн",
|
||||
"horizon.splitscreen.prompt.join.yes": "Пӗрлешӗр",
|
||||
"horizon.splitscreen.prompt.join.as_p1": "P1 пек выля",
|
||||
"horizon.splitscreen.prompt.join.no": "Ҫук",
|
||||
"horizon.splitscreen.prompt.lost": "%s: контроллер татӑлнӑ",
|
||||
"horizon.splitscreen.prompt.lost.use_another": "Урӑххипе усӑ курӑр",
|
||||
"horizon.splitscreen.prompt.lost.leave": "Тухса кай",
|
||||
"horizon.splitscreen.setup.help.give_up_pad": "Сирӗн контроллер сире илсе ҫӳреме пӑрахать те (А) ушкӑна кӗме сӗнет.",
|
||||
"horizon.splitscreen.setup.note.held_at": "%s to %s: А ӑна кунта пӑрахать, В ӑна каялла хурать.",
|
||||
"horizon.splitscreen.setup.note.held": "%s ҫӗкленӗ: сулахай/сылтӑм ӑҫта илсе тухать, А ӳкерет, В ӑна каялла хурать.",
|
||||
"horizon.splitscreen.online_only": "Ку сервер онлайн режимра: офлайн профильсем унта кӗреймеҫҫӗ, кашни выляканӑн хӑйӗн Minecraft аккаунчӗ кирлӗ.",
|
||||
"horizon.splitscreen.own_account": "Ку сервера кашни выляканӑн хӑйӗн Minecraft аккаунчӗ кирлӗ",
|
||||
"horizon.splitscreen.local_only": "Ытти вылякансем ҫак сервера хӑйсен Minecraft аккаунчӗпе кӑна кӗме пултараҫҫӗ: офлайн профильсем сирӗн тӗнчере, LAN-ра е сирӗн вырӑнти сетьри серверта выляҫҫӗ.",
|
||||
"Hides models behind opaque blocks. Async checks off-thread; entities tick.": "Модельсене тӗксӗм блоксем хыҫне пытарать. Асинхронлӑ ҫипрен тухнине тӗрӗслет; субъектсем тик.",
|
||||
"Block Entities": "Блок субъекчӗсем",
|
||||
"Shulker Boxes": "Шулькер ещӗкӗсем",
|
||||
"Reuses settled boxes; lid movement stays animated.": "Ҫирӗплетнӗ ещӗксемпе тепӗр хут усӑ курать; хупӑлча хусканӑвӗ чӗрӗ юлать.",
|
||||
"Signs": "Паллӑсем",
|
||||
"Reuses sign text until text, light, or font changes.": "Текст, ҫутӑ е шрифт улшӑниччен паллӑ текстне тепӗр хут усӑ курать.",
|
||||
"Decorated Pots": "Илемлетнӗ чӳлмексем",
|
||||
"Reuses still pots; break wobble and sherd changes redraw.": "Ҫирӗп чӳлмексемпе тепӗр хут усӑ курать; ҫӗмӗрме, сулланма тата ҫӗмӗрме улшӑнусем ҫӗнӗрен ӳкерме.",
|
||||
"Bells": "Шӑнкӑравсем",
|
||||
"Reuses still bells; ringing stays animated.": "Ҫӗнӗрен усӑ курать шӑнкӑравсем; шӑнкӑртатни чӗрӗ юлать.",
|
||||
"Chests": "Арчасем",
|
||||
"Reuses closed chests; moving lids stay animated.": "Хупӑ арчасене тепӗр хут усӑ курать; куҫакан хупӑлчасем чӗрӗ юлаҫҫӗ.",
|
||||
"Banners": "Баннерсем",
|
||||
"Reuses poles; flags and pattern layers still update.": "Юпасене тепӗр хут усӑ курать; ялавсемпе ӳкерчӗк сийӗсем халӗ те ҫӗнелеҫҫӗ.",
|
||||
"Copper Golem Statues": "Пӑхӑр голем статуйисем",
|
||||
"Reuses statue geometry until its block state changes.": "Статуя геометрине унӑн блок тӑрӑмӗ улшӑниччен тепӗр хут усӑ курать.",
|
||||
"Leaf Culling": "Ҫулҫӑсене касасси",
|
||||
"Every leaf face. Vanilla's fancy leaves.": "Кашни ҫулҫӑ пит-куҫӗ. Ваниль ҫулҫисем.",
|
||||
"Distant Plant Dither": "Инҫетри ӳсентӑран чӗтренет",
|
||||
"Keeps fine plants in high-res packs from fading far away.": "Пысӑк ҫивӗчлӗхлӗ пакетсенчи вӗтӗ ӳсентӑрансене инҫете сӳнме памасть.",
|
||||
"Screenshot Quality": "Скриншот пахалӑхӗ",
|
||||
"F2 screenshots at this many times the game's resolution. Higher takes longer.": "F2 скриншочӗсем ҫак вӑйӑ татӑклӑхӗнчен нумай хут пысӑкрах. Ҫӳлтиреххи вӑраха тӑсӑлать.",
|
||||
"Frame Generation": "Кадр генерацийӗ",
|
||||
"Shows a made-up frame between each two real ones: smoother, a little more lag.": "Кашни икӗ чӑн-чӑн хушшинче тунӑ кадра кӑтартать: тикӗсрех, кӑштах кая юлса.",
|
||||
"Shadow Cache": "Мӗлке кэшӗ",
|
||||
"Reuses the pack shadow map when sun, view and world match. Off by default.": "Хӗвел, курӑну тата тӗнче пӗр пек чухне мӗлке карттипе тепӗр хут усӑ курать. Выключен по умолчанию.",
|
||||
"Find BlueMap": "BlueMap тупӑр",
|
||||
"On servers, finds their BlueMap web map for far terrain. Next join.": "Серверсем ҫинче инҫетри ҫӗр ҫинчи BlueMap веб-карттине тупать. Тепӗр хут хутшӑнӑр.",
|
||||
"BlueMap Radius": "BlueMap радиусӗ",
|
||||
"How far around you BlueMap tiles are downloaded. Next join.": "Сирӗн тавра BlueMap плиткисене мӗн таран скачать тӑваҫҫӗ. Тепӗр хут хутшӑнӑр.",
|
||||
"Synchronous": "Синхронлӑ",
|
||||
"Asynchronous": "Асинхронлӑ",
|
||||
"Solid": "Хытӑ",
|
||||
"Solid Aggressive": "Ҫирӗп агрессивлӑ",
|
||||
"Hollow": "Пушӑ",
|
||||
"Leaves fully inside a canopy draw solid: fewer see-through layers.": "Ҫулҫӑсем ҫивитти ӑшӗнче туллин ҫирӗпленсе лараҫҫӗ: витӗр курӑнакан сийсем сахалрах.",
|
||||
"Leaves with one open side draw solid too: faster, chunkier edges.": "Пӗр уҫӑ енлӗ ҫулҫӑсем те ҫирӗп ӳкереҫҫӗ: хӑвӑртрах, ҫирӗпрех хӗррисем.",
|
||||
"Drops faces between leaves: faster, but gaps look through.": "Ҫулҫӑсем хушшинчи пит-куҫа тумлатать: хӑвӑртрах, анчах хушӑксем витӗр курӑнаҫҫӗ.",
|
||||
"Hotbar: Previous Slot": "Hotbar: Унчченхи слот",
|
||||
"Hotbar: Next Slot": "Hotbar: Тепӗр слот",
|
||||
"horizon.agent.connected.one": "Ҫыхӑннӑ: 1 агент ҫыхӑнӑвӗ",
|
||||
"horizon.agent.connected.many": "Ҫыхӑннӑ: %s агент ҫыхӑнӑвӗсем",
|
||||
"horizon.agent.connected.one_ago": "Ҫыхӑннӑ: 1 агент ҫыхӑнӑвӗ, юлашки команда %s s каялла",
|
||||
"horizon.agent.connected.many_ago": "Ҫыхӑннӑ: %s агент ҫыхӑнӑвӗсем, юлашки команда %s s каялла",
|
||||
"horizon.agent.waiting": "Агента кӗтетӗп.",
|
||||
"horizon.agent.off": "Ҫук: агентсем ҫак вӑййа ҫитеймеҫҫӗ.",
|
||||
"horizon.agent.session_opened": "Ку сеанс валли вӑййа пуҫарса янӑ программа уҫнӑ.",
|
||||
"horizon.agent.socket": "Сокет: %s (унӑн тулли ҫулӗ валли детальсене копиле)",
|
||||
"horizon.agent.local_only": "Вырӑнти кӑна: ку компьютер ҫинчи агентсем, нихӑҫан та сеть мар.",
|
||||
"%s nits": "%s нитс",
|
||||
"Auto (%s nits)": "Авто (%s нит)",
|
||||
"%.2f nits": "%.2f нитс",
|
||||
"Hides models behind opaque blocks. Entities update. Off with custom packs.": "Модельсене тӗксӗм блоксем хыҫне пытарать. Субъектсем ҫӗнелеҫҫӗ. Ятарлӑ пакетсемпе тухӑр.",
|
||||
"horizon.extras.repro_keys": "Ҫырса илмелли кӗске ҫулсем",
|
||||
"horizon.extras.repro_keys.tooltip": "F3+R репро ҫырӑва пуҫлать е чарать, F3+E вара хӑйӗн ҫыххине ҫырать. Стандартпа ӗҫлемен: ҫыру тӗнчене копилет.",
|
||||
"horizon.agent.record_session": "Ҫырса илме пуҫла",
|
||||
"horizon.agent.record_stop": "Ҫырса илме чарӑнӑр",
|
||||
"horizon.agent.export_repro": "Репродукци пуххине экспортла",
|
||||
"horizon.repro.started": "Ҫырса илме пуҫларӗҫ; F3+R ӑна чарать те ҫыхӑ ҫырать.",
|
||||
"horizon.repro.stopped": "Ҫырса илме чарӑннӑ: %s",
|
||||
"horizon.repro.bundle": "Репро пуххи: %s",
|
||||
"horizon.repro.error": "Репро: %s",
|
||||
"horizon.repro.no_recording": "Хальлӗхе экспортлама ҫыру ҫук.",
|
||||
"horizon.repro.replay_started": "Реплей пуҫланчӗ: %s",
|
||||
"horizon.pack.addInfo": "Modrinth-ран пуҫласа ресурс пакетне хушӑр",
|
||||
"horizon.pack.addWorking": "Modrinth ыйтатӑп...",
|
||||
"horizon.pack.addNone": "Ресурс пакетӗсем тупӑнман",
|
||||
"horizon.pack.addTitle": "Ресурссен пакетне хушӑр",
|
||||
"horizon.pack.install": "Установка",
|
||||
"horizon.pack.installing": "Установка",
|
||||
"horizon.pack.installed": "вырнаҫтарнӑ",
|
||||
"horizon.pack.search": "Шырав",
|
||||
"horizon.pack.searchHint": "Шырав Modrinth...",
|
||||
"horizon.pack.filters": "Фильтрсем",
|
||||
"horizon.pack.filter.realistic": "Чӑн пурнӑҫри пек",
|
||||
"horizon.pack.filter.simplistic": "Ансат",
|
||||
"horizon.pack.filter.vanillaLike": "Ваниль евӗрлӗ",
|
||||
"horizon.pack.filter.x16": "16х",
|
||||
"horizon.pack.filter.x32": "32х",
|
||||
"horizon.pack.filter.x64": "64х",
|
||||
"horizon.pack.addFailed": "Пакета хушма май килмерӗ: %s",
|
||||
"horizon.extras.header.cosmetics": "Косметика",
|
||||
"horizon.extras.cosmetics_mine": "Манӑн косметика",
|
||||
"horizon.extras.cosmetics_mine.tooltip": "Пытарнӑ: кашни Horizon вылякан сире косметикӑсӑр курать, эсир те ҫав шутра. Пуҫкаҫӑн гардеробӗнчи пекех переключатель.",
|
||||
"horizon.extras.cosmetics_others": "Ытти вылякансен косметики",
|
||||
"horizon.extras.cosmetics_others.tooltip": "Ытти Horizon вылякансем мӗн тӑхӑнаҫҫӗ: пурте, вӗсен ячӗсен стилӗсем ҫеҫ, е нимӗн те мар. Вӑрттӑн, вӑйӑ нихҫан та вӗсем мӗн тӑхӑннине ыйтмасть.",
|
||||
"horizon.extras.cosmetics_auras": "Ыттисен аурисем тата йӗрӗсем",
|
||||
"horizon.extras.cosmetics_auras.tooltip": "Ытти вылякансем тӑхӑнакан аурӑсемпе йӗрсем. Выключен по умолчанию.",
|
||||
"horizon.extras.cosmetics.shown": "Кӑтартнӑ",
|
||||
"horizon.extras.cosmetics.hidden": "Пытарнӑ",
|
||||
"horizon.extras.cosmetics.name_tags": "Ят паллисем кӑна"
|
||||
}
|
||||
@@ -0,0 +1,467 @@
|
||||
{
|
||||
"horizon.options.controller": "Rheolydd",
|
||||
"horizon.options.vibration": "Dirgryniad",
|
||||
"horizon.options.adaptive_triggers": "Sbardunau Addasol",
|
||||
"horizon.options.lightbar": "Bar golau",
|
||||
"horizon.options.look_sensitivity": "Sensitifrwydd edrych",
|
||||
"horizon.options.invert_x": "Edrych Gwrthdro X",
|
||||
"horizon.options.invert_y": "Edrych Gwrthdro Y",
|
||||
"horizon.options.sneak_button": "Botwm sleifio",
|
||||
"horizon.options.move_deadzone": "Parth marw symud",
|
||||
"horizon.options.look_deadzone": "Parth marw edrych",
|
||||
"horizon.options.button_glyphs": "Glyffau Botwm",
|
||||
"horizon.options.on_screen_keyboard": "Bysellfwrdd Ar-Sgrin",
|
||||
"horizon.options.chat_delay": "Oedi Sgwrsio",
|
||||
"horizon.options.lightbar.health": "Iechyd",
|
||||
"horizon.options.lightbar.dimension": "Dimensiwn",
|
||||
"horizon.options.unavailable": "Nid yw'r nodwedd hon ar gael eto yn Horizon.",
|
||||
"horizon.options.search": "Gosodiadau chwilio...",
|
||||
"horizon.pages.shader_packs": "Pecynnau Shader",
|
||||
"horizon.pages.shader_options": "Opsiynau Shader",
|
||||
"horizon.pages.controller": "Gosodiadau Rheolydd",
|
||||
"horizon.pages.controller_binds": "Rhwymiadau Rheolydd",
|
||||
"horizon.pages.extras": "Horizon Ychwanegiadau",
|
||||
"horizon.pages.settings": "Horizon Gosodiadau",
|
||||
"horizon.pages.agent": "AI Asiant",
|
||||
"horizon.split.leave": "Gadael",
|
||||
"horizon.pages.split_settings": "Gosodiadau Sgrin Hollt",
|
||||
"horizon.pages.split_profiles": "Pwy sy'n chwarae?",
|
||||
"horizon.pages.split_setup": "Gosod Sgrîn Hollt",
|
||||
"horizon.pages.music": "Cerddoriaeth",
|
||||
"horizon.pages.music.menu": "Bwydlen",
|
||||
"horizon.pages.music.overworld": "Gor-fyd",
|
||||
"horizon.pages.music.creative": "Creadigol",
|
||||
"horizon.pages.music.underwater": "Dan y dwr",
|
||||
"horizon.pages.music.end": "Y Diwedd",
|
||||
"horizon.pages.music.credits": "Credydau",
|
||||
"horizon.pages.music.overworld_biomes": "Biomau gor-fyd",
|
||||
"horizon.pages.music.nether_biomes": "Na biomau chwaith",
|
||||
"horizon.pages.music.end_biomes": "Diwedd biomau",
|
||||
"horizon.pages.music.other": "Cerddoriaeth arall",
|
||||
"horizon.pages.music.empty": "Dim traciau cerddoriaeth: nid yw synau'r gêm yn cael eu llwytho.",
|
||||
"horizon.pages.music.tooltip": "Y traciau adeiledig, fesul sefyllfa: chwaraewch un nawr, neu trowch i ffwrdd fel bod y gêm yn peidio â'i ddewis.",
|
||||
"horizon.pages.settings.tooltip": "Gosodiadau Horizon ei hun: graffeg, rheolyddion, pethau ychwanegol a mods.",
|
||||
"horizon.pages.graphics.tooltip": "Graffeg, yn syml: mae pob lleoliad yn dweud beth mae'n ei gostio.",
|
||||
"horizon.pages.graphics_advanced.tooltip": "Pob gosodiad graffeg, Horizon wedi'i gynnwys, gyda'r hyn y mae pob un yn ei gostio.",
|
||||
"horizon.pages.controller.tooltip": "Rheolyddion: eu botymau, ffyn, dirgryniad a llywio dewislen.",
|
||||
"horizon.pages.extras.tooltip": "Ychwanegiadau dewisol, i gyd i ffwrdd yn ddiofyn: mae'r gêm yn aros yn fanila nes i chi droi un ymlaen.",
|
||||
"horizon.pages.agent.tooltip": "Gadewch i'ch asiant AI eich hun chwarae: horizon-ctl a chleientiaid MCP ar y cyfrifiadur hwn.",
|
||||
"horizon.pages.split_profiles.tooltip": "Pwy sy'n chwarae: proffil a gedwir yn y ffolder gêm hon.",
|
||||
"horizon.pages.split_setup.tooltip": "Y ffenestri a'r monitorau, a phwy sy'n chwarae ble.",
|
||||
"horizon.pages.shader_packs.tooltip": "Pecynnau cysgodi o'r ffolder shaderpacks: Horizon ei hun a'r rhai yn y shaders/fformat. Mae un yn rhedeg ar y tro.",
|
||||
"horizon.pages.mods.tooltip": "Mods wedi'u gwneud ar gyfer Horizon, o'r ffolder horizon-mods. Mae pob un yn rhedeg mewn blwch tywod ac yn aros i ffwrdd nes i chi ei droi ymlaen.",
|
||||
"horizon.pages.open.graphics": "Graffeg...",
|
||||
"horizon.pages.open.graphics_advanced": "Graffeg Uwch...",
|
||||
"horizon.pages.open.shader_packs": "Pecynnau Shader...",
|
||||
"horizon.pages.open.controller": "Gosodiadau Rheolydd...",
|
||||
"horizon.pages.open.split_setup": "Sgrin hollti...",
|
||||
"horizon.pages.open.extras": "Ychwanegion...",
|
||||
"horizon.pages.open.agent": "Asiant AI...",
|
||||
"horizon.pages.open.horizon_graphics": "Horizon Graffeg...",
|
||||
"horizon.pages.open.controller_binds": "Rheolydd yn rhwymo...",
|
||||
"horizon.pages.open.horizon_settings": "Horizon Gosodiadau...",
|
||||
"horizon.pages.open.music": "Cerddoriaeth...",
|
||||
"horizon.mods.empty": "Dim mods: rhowch ffeiliau .hmod yn y ffolder horizon-mods",
|
||||
"horizon.mods.stopped": " (Wedi stopio)",
|
||||
"horizon.mods.not_built": " (Heb ei adeiladu)",
|
||||
"horizon.mods.settings": "Gosodiadau",
|
||||
"horizon.mods.in_world": " (gadewch y byd i newid)",
|
||||
"horizon.mods.open_folder": "Agor Ffolder Mod",
|
||||
"horizon.shader_packs.empty": "Dim pecynnau lliwiwr: rhowch nhw yn y ffolder shaderpacks",
|
||||
"horizon.shader_options.open": "Opsiynau Shader...",
|
||||
"horizon.shader_options.profile": "Proffil",
|
||||
"horizon.shader_options.loading": "Darllen opsiynau'r pecyn lliwiwr...",
|
||||
"horizon.agent.copy_details": "Copïo Manylion Cysylltiad",
|
||||
"horizon.multiplayer.join": "Ymuno",
|
||||
"horizon.multiplayer.cancel_reconnecting": "Canslo Ailgysylltu",
|
||||
"horizon.multiplayer.join_friend": "Ymunwch â Ffrind",
|
||||
"horizon.multiplayer.invite_code": "Cod Gwahodd",
|
||||
"horizon.multiplayer.relay": "Cyfnewid (dewisol)",
|
||||
"Preset": "Rhagosodedig",
|
||||
"LOD Distance": "Pellter LOD",
|
||||
"Far Detail": "Manylyn Pell",
|
||||
"Cave Culling": "Difa Ogof",
|
||||
"Entity Culling": "Difa Endid",
|
||||
"Chunk Updates": "Diweddariadau Chunk",
|
||||
"Upload Budget": "Uwchlwytho Cyllideb",
|
||||
"Sky": "Awyr",
|
||||
"Fog": "Niwl",
|
||||
"Weather": "Tywydd",
|
||||
"Animated Textures": "Gweadau Animeiddiedig",
|
||||
"Present Mode": "Modd Presennol",
|
||||
"Frame Pacing": "Cyflymder Ffrâm",
|
||||
"Worker Threads": "Trywyddau Gweithiwr",
|
||||
"Resolution Scale": "Graddfa Datrysiad",
|
||||
"Anti-aliasing": "Gwrth-aliasing",
|
||||
"Paper White": "Papur Gwyn",
|
||||
"Peak Brightness": "Disgleirdeb Brig",
|
||||
"Black Level": "Lefel Ddu",
|
||||
"UI Brightness": "Disgleirdeb UI",
|
||||
"Battery Mode": "Modd Batri",
|
||||
"Graphics API": "Graffeg API",
|
||||
"Translucent Batching": "Sypynnu Tryloyw",
|
||||
"Performance Overlay": "Troshaen Perfformiad",
|
||||
"Full Detail Distance": "Pellter Manylion Llawn",
|
||||
"On": "Ar",
|
||||
"Off": "I ffwrdd",
|
||||
"Unlimited": "Diderfyn",
|
||||
"Performance": "Perfformiad",
|
||||
"Balanced": "Cytbwys",
|
||||
"Quality": "Ansawdd",
|
||||
"Ultra Performance": "Perfformiad Ultra",
|
||||
"Native": "Brodorol",
|
||||
"Full": "Llawn",
|
||||
"Reduced": "Gostyngedig",
|
||||
"Efficient": "Effeithlon",
|
||||
"Precise": "Cywir",
|
||||
"Mailbox": "Blwch post",
|
||||
"Immediate": "Ar unwaith",
|
||||
"FPS and Graph": "FPS a Graff",
|
||||
"No cost": "Dim cost",
|
||||
"Low cost": "Cost isel",
|
||||
"Medium cost": "Cost ganolig",
|
||||
"High cost": "Cost uchel",
|
||||
"Saves time": "Yn arbed amser",
|
||||
"Graphics": "Graffeg",
|
||||
"Done": "Wedi'i wneud",
|
||||
"This feature is not yet available in Horizon.": "Nid yw'r nodwedd hon ar gael eto yn Horizon.",
|
||||
"Your display or system doesn't offer HDR output.": "Nid yw eich arddangosfa neu system yn cynnig allbwn HDR.",
|
||||
"Turn HDR on to use it.": "Trowch HDR ymlaen i'w ddefnyddio.",
|
||||
"Your GPU or graphics API doesn't support it.": "Nid yw eich GPU neu API graffeg yn ei gefnogi.",
|
||||
"%s chunks": "%s talpiau",
|
||||
"%s per frame": "%s fesul ffrâm",
|
||||
"%s MiB/frame": "%s MiB/ffrâm",
|
||||
"%s KiB/frame": "%s KiB/ffrâm",
|
||||
"Full-detail terrain range. LOD Distance can extend local worlds farther.": "Amrediad tir manwl llawn. Gall pellter LOD ymestyn bydoedd lleol ymhellach.",
|
||||
"Coarse distant terrain in local worlds. Integrated GPUs stop at 128 chunks.": "Tir garw pell yn y bydoedd lleol. Mae GPUs integredig yn stopio ar 128 talpiau.",
|
||||
"Reduced draws far terrain coarser: faster on this integrated GPU.": "Llai yn tynnu tir llawer mwy bras: yn gyflymach ar y GPU integredig hwn.",
|
||||
"Reduced draws far terrain coarser, for GPUs it slows down.": "Mae llai yn tynnu tir llawer mwy bras, ar gyfer GPUs mae'n arafu.",
|
||||
"Field of view. Wider shows more terrain at once.": "Maes golygfa. Yn ehangach yn dangos mwy o dir ar unwaith.",
|
||||
"Caps frames per second; a cap saves power and heat.": "Fframiau capiau yr eiliad; mae cap yn arbed pŵer a gwres.",
|
||||
"Waits for the display's refresh: no tearing, a little latency.": "Aros am adnewyddu'r arddangosfa: dim rhwygo, ychydig o hwyrni.",
|
||||
"Size of menus and the HUD.": "Maint y bwydlenni a'r HUD.",
|
||||
"Sets the options below together. Changing one makes it Custom.": "Yn gosod yr opsiynau isod gyda'i gilydd. Mae newid un yn ei gwneud yn Custom.",
|
||||
"Lava, fire and sunlight shine brighter than white. Needs an HDR display.": "Mae lafa, tân a golau'r haul yn disgleirio'n fwy disglair na gwyn. Angen arddangosfa HDR.",
|
||||
"Your display's darkest black. 0 for OLED; LCDs glow a little.": "Du tywyllaf eich arddangosfa. 0 ar gyfer OLED; Mae LCDs yn tywynnu ychydig.",
|
||||
"How bright highlights get. Auto: the peak your system reports.": "Sut mae uchafbwyntiau disglair yn ei gael. Auto: yr uchafbwynt y mae eich system yn ei adrodd.",
|
||||
"How bright white paper and menus look. Auto: your desktop's white.": "Sut olwg sydd ar bapur gwyn llachar a bwydlenni. Auto: gwyn eich bwrdd gwaith.",
|
||||
"How bright the HUD and menus are, against paper white.": "Pa mor llachar yw'r HUD a'r bwydlenni, yn erbyn papur gwyn.",
|
||||
"How far mobs, crops and machines keep working. CPU time.": "Pa mor bell y mae mobs, cnydau a pheiriannau yn dal i weithio. Amser CPU.",
|
||||
"How far away mobs and items are drawn, as a share of normal.": "Pa mor bell i ffwrdd mae mobs ac eitemau yn cael eu tynnu, fel cyfran o'r arferol.",
|
||||
"Skips terrain hidden behind closed sections. Off costs a lot.": "Sgipiau tir wedi'i guddio y tu ôl i adrannau caeedig. Mae i ffwrdd yn costio llawer.",
|
||||
"Hides entities behind opaque blocks.": "Yn cuddio endidau y tu ôl i flociau afloyw.",
|
||||
"No entity occlusion culling.": "Dim difa endid occlusion.",
|
||||
"CPU occlusion test runs this frame.": "Mae prawf occlusion CPU yn rhedeg y ffrâm hon.",
|
||||
"Occlusion checks run on a worker thread.": "Mae gwiriadau Occlusion yn rhedeg ar edefyn gweithiwr.",
|
||||
"Meshed sections uploaded per frame. Lower is smoother while loading.": "Adrannau rhwyllog wedi'u huwchlwytho fesul ffrâm. Mae is yn llyfnach wrth lwytho.",
|
||||
"Soft shadows in corners. Costs chunk building time only.": "Cysgodion meddal mewn corneli. Mae'n costio talp o amser adeiladu yn unig.",
|
||||
"Smaller copies of block textures for distant terrain: less shimmer.": "Copïau llai o weadau bloc ar gyfer tir pell: llai o sglein.",
|
||||
"Blends grass and water colours across biomes when building chunks.": "Cyfuno lliwiau glaswellt a dŵr ar draws biomau wrth adeiladu talpiau.",
|
||||
"Cloud layer: off, flat (fast) or 3D (fancy).": "Haen cwmwl: i ffwrdd, fflat (cyflym) neu 3D (ffansi).",
|
||||
"How far clouds reach, in chunks.": "Pa mor bell y mae cymylau'n cyrraedd, mewn talpiau.",
|
||||
"Draws the sky, sun, moon and stars.": "Yn darlunio'r awyr, yr haul, y lleuad a'r sêr.",
|
||||
"Distance fog. Off shows the edge of the loaded world.": "Niwl pellter. Mae Off yn dangos ymyl y byd llwythog.",
|
||||
"Draws rain and snow.": "Yn tynnu glaw ac eira.",
|
||||
"How far rain and snow fall around you.": "Pa mor bell y mae glaw ac eira yn disgyn o'ch cwmpas.",
|
||||
"How many particles effects spawn.": "Faint o effeithiau gronynnau sy'n silio.",
|
||||
"Round shadows under mobs and items.": "Cysgodion crwn o dan mobs ac eitemau.",
|
||||
"Leaves with see-through gaps. Off draws them solid.": "Dail gyda bylchau amlwg. I ffwrdd yn eu tynnu solet.",
|
||||
"Sorts water and glass more exactly behind each other.": "Didoli dŵr a gwydr yn fwy union y tu ôl i'w gilydd.",
|
||||
"Which chunk rebuilds wait for the frame: none, nearby or yours.": "Pa dalp ailadeiladu aros am y ffrâm: dim, gerllaw neu eich un chi.",
|
||||
"Animates water, lava, fire and other moving textures.": "Yn animeiddio dŵr, lafa, tân a gweadau symudol eraill.",
|
||||
"World pixels per screen pixel. Below 100% is faster on the GPU.": "Picsel y byd fesul picsel sgrin. Mae llai na 100% yn gyflymach ar y GPU.",
|
||||
"Smooths jagged edges. FXAA: softer. TAA: smoothest, moving things may trail.": "Llyfn ymylon miniog. FXAA: meddalach. TAA: mae'n bosibl y bydd pethau llyfn, symudol yn dilyn.",
|
||||
"Renders the world smaller and rebuilds it with TAA. Faster, softer.": "Yn gwneud y byd yn llai ac yn ei ailadeiladu gyda TAA. Cyflymach, meddalach.",
|
||||
"HDR output on an HDR display: lava, fire and sunlight shine brighter.": "Allbwn HDR ar arddangosfa HDR: lafa, tân a golau haul yn disgleirio'n fwy disglair.",
|
||||
"How frames reach the screen while VSync is off.": "Sut mae fframiau'n cyrraedd y sgrin tra bod VSync i ffwrdd.",
|
||||
"Efficient sleeps until the next frame; Precise spins, like vanilla.": "Cysgu'n effeithlon tan y ffrâm nesaf; Troelli manwl gywir, fel fanila.",
|
||||
"Fills the screen (borderless).": "Yn llenwi'r sgrin (heb ffiniau).",
|
||||
"Brightens dark places.": "Yn goleuo lleoedd tywyll.",
|
||||
"Lowers the frame rate when minimised, or idle too.": "Yn gostwng y gyfradd ffrâm pan gaiff ei lleihau, neu'n segur hefyd.",
|
||||
"Sways the view while walking.": "Troi'r olygfa wrth gerdded.",
|
||||
"Fades newly loaded chunks in.": "Yn pylu darnau newydd eu llwytho i mewn.",
|
||||
"Darkens the screen's edges.": "Tywyllu ymylon y sgrin.",
|
||||
"Shows when the world saves.": "Yn dangos pan fydd y byd yn arbed.",
|
||||
"Shows attack cooldown.": "Yn dangos ymosodiad ymosodiad.",
|
||||
"60 FPS cap (30 in menus or unfocused), half the workers: less power.": "Cap FPS 60 (30 mewn bwydlenni neu heb ffocws), hanner y gweithwyr: llai o bŵer.",
|
||||
"Threads that generate, light and mesh chunks. Next start.": "Trywyddau sy'n cynhyrchu darnau ysgafn a rhwyll. Cychwyn nesaf.",
|
||||
"Vulkan, then DirectX 12 (Windows) or OpenGL (Linux) where it fails. Next start.": "Vulkan, yna DirectX 12 (Windows) neu OpenGL (Linux) lle mae'n methu. Cychwyn nesaf.",
|
||||
"Water and glass in one buffer: fewer draw calls, a bit more VRAM. Next start.": "Dŵr a gwydr mewn un byffer: llai o alwadau tynnu, ychydig mwy o VRAM. Cychwyn nesaf.",
|
||||
"Mesh data sent to the GPU per frame. Lower is smoother while loading.": "Anfonir data rhwyll i'r GPU fesul ffrâm. Mae is yn llyfnach wrth lwytho.",
|
||||
"Frame rate and frame times over the game, with a graph.": "Cyfradd ffrâm ac amseroedd ffrâm dros y gêm, gyda graff.",
|
||||
"horizon.multiplayer.finding_friend": "Dod o hyd i fyd eich ffrind...",
|
||||
"horizon.multiplayer.not_signed_in": "Mae'r gweinydd hwn yn y modd ar-lein. Mewngofnodwch gyda'ch cyfrif Microsoft yn y lansiwr Horizon i ymuno ag ef.",
|
||||
"horizon.multiplayer.invalid_address": "Cyfeiriad gweinydd annilys: %s",
|
||||
"horizon.multiplayer.connected_friend_direct": "Wedi'i gysylltu'n syth â'ch ffrind...",
|
||||
"horizon.multiplayer.connected_friend_relay": "Wedi'i gysylltu â'ch ffrind trwy'r ras gyfnewid ...",
|
||||
"General": "Cyffredinol",
|
||||
"Advanced": "Uwch",
|
||||
"Undo": "Dadwneud",
|
||||
"Search options": "Dewisiadau chwilio",
|
||||
"Shortcut": "Llwybr byr",
|
||||
"Distance": "Pellter",
|
||||
"Display": "Arddangos",
|
||||
"Interface": "Rhyngwyneb",
|
||||
"Sky and weather": "Awyr a thywydd",
|
||||
"Lighting and entities": "Goleuadau ac endidau",
|
||||
"Textures": "Gweadau",
|
||||
"Image": "Delwedd",
|
||||
"Chunk loading": "Llwytho i lawr",
|
||||
"Culling": "Difa",
|
||||
"Power": "Grym",
|
||||
"Frames": "Fframiau",
|
||||
"Overlay": "Troshaen",
|
||||
"Output": "Allbwn",
|
||||
"Brightness": "Disgleirdeb",
|
||||
"How far you see, the window and the HUD.": "Pa mor bell y gwelwch, y ffenestr a'r HUD.",
|
||||
"The sky and weather, lighting, textures and the image.": "Yr awyr a'r tywydd, goleuo, gweadau a'r ddelwedd.",
|
||||
"Chunk loading, culling and power use.": "Llwytho talp, difa a defnydd pŵer.",
|
||||
"How frames reach the screen, and the performance overlay.": "Sut mae fframiau'n cyrraedd y sgrin, a'r troshaen perfformiad.",
|
||||
"Brighter-than-white output on an HDR display.": "Allbwn mwy disglair na gwyn ar arddangosfa HDR.",
|
||||
"Results for \"%s\"": "Canlyniadau ar gyfer \"%s\"",
|
||||
"No settings match.": "Dim gosodiadau yn cyfateb.",
|
||||
"horizon.title.not_affiliated": "Ddim yn gysylltiedig â Mojang na Microsoft",
|
||||
"horizon.extras.header.lighting": "Goleuo",
|
||||
"horizon.extras.header.third_person": "Trydydd person",
|
||||
"horizon.extras.header.particles": "Gronynnau",
|
||||
"horizon.extras.header.inventory": "Stocrestr",
|
||||
"horizon.extras.header.chat": "Sgwrsio",
|
||||
"horizon.extras.header.multiplayer": "Aml-chwaraewr",
|
||||
"horizon.extras.header.sound": "Sain",
|
||||
"horizon.extras.header.menus": "Bwydlenni",
|
||||
"horizon.extras.fullbright": "Llawnbright",
|
||||
"horizon.extras.dynamic_lights": "Goleuadau deinamig",
|
||||
"horizon.extras.own_name_tag": "Tag enw eich hun",
|
||||
"horizon.extras.hide_block_particles": "Cuddio gronynnau bloc-toriad",
|
||||
"horizon.extras.auto_reconnect": "Ailgysylltu'n awtomatig",
|
||||
"horizon.extras.ui_sound_reserve": "Cadwch sianeli ar gyfer synau UI",
|
||||
"horizon.extras.music_page": "Tudalen cerddoriaeth",
|
||||
"horizon.extras.mouse_tweaks": "Rheolaethau Llygoden Tweaks",
|
||||
"horizon.extras.mouse_tweaks_wheel": "Olwyn sgrolio yn symud eitemau",
|
||||
"horizon.extras.sort": "Botymau didoli",
|
||||
"horizon.extras.sort_key": "Allwedd didoli",
|
||||
"horizon.extras.no_ai": "Dim AI",
|
||||
"horizon.extras.agent_control": "Rheoli Asiant",
|
||||
"horizon.extras.discord_presence": "Presenoldeb Cyfoethog Discord",
|
||||
"horizon.extras.splitscreen": "Sgrîn hollt",
|
||||
"horizon.extras.chat_animation": "Sgwrs esmwyth",
|
||||
"horizon.extras.chat_indicator": "Dangosydd neges",
|
||||
"horizon.extras.wheel_cycles_settings": "Gosodiadau newid olwyn sgrolio",
|
||||
"horizon.extras.pack_browser": "Porwr pecyn adnoddau",
|
||||
"horizon.extras.fullbright.tooltip": "Dangoswch flociau ac endidau ar olau llawn, hyd yn oed mewn ardaloedd tywyll.",
|
||||
"horizon.extras.dynamic_lights.tooltip": "Mae fflachlampau a ffynonellau golau eraill sy'n cael eu dal, eu gollwng neu ar dân yn cynnau'r blociau o'u cwmpas.",
|
||||
"horizon.extras.own_name_tag.tooltip": "Yn dangos eich enw uwch eich pen yn y trydydd person, fel y mae chwaraewyr eraill yn ei weld. Wedi'i guddio pan fydd y gweinydd yn cuddio enwau eich tîm neu pan fyddwch chi'n anweledig.",
|
||||
"horizon.extras.hide_block_particles.tooltip": "Yn cuddio'r gronynnau malurion sy'n byrstio o floc sydd wedi torri ac yn dadfeilio'r un rydych chi'n ei gloddio. Mae gronynnau eraill yn aros.",
|
||||
"horizon.extras.auto_reconnect.tooltip": "Yn ailymuno â gweinydd ar ôl colli cysylltiad neu ailgychwyn, byth ar ôl cic neu waharddiad.",
|
||||
"horizon.extras.ui_sound_reserve.tooltip": "Mae synau yn y byd yn gadael 16 o'r 247 sianel sain yn rhydd, felly ni all llifogydd ohonynt (ffrwydrad mawr) dawelu cliciau dewislen.",
|
||||
"horizon.extras.music_page.tooltip": "Mae Music & Sounds yn cael tudalen Cerddoriaeth...: chwaraewch unrhyw drac adeiledig nawr, neu trowch un i ffwrdd fel bod y gêm yn peidio â'i ddewis. Does dim byd yn newid nes i chi droi trac i ffwrdd.",
|
||||
"horizon.extras.mouse_tweaks.tooltip": "Mae llusgo dde yn gosod un fesul slot, mae llusgiad chwith yn casglu'r eitem a ddelir, mae Shift + llusgo chwith yn symud pob slot.",
|
||||
"horizon.extras.mouse_tweaks_wheel.tooltip": "Mae Down yn anfon un eitem o'r slot i'r ochr arall, i fyny yn dod ag un yn ôl.",
|
||||
"horizon.extras.sort.tooltip": "Trefnu'r rhestr eiddo, cistiau, casgenni, cistiau ender a blychau shulker yn nhrefn tabiau creadigol, gan uno staciau.",
|
||||
"horizon.extras.sort_key.tooltip": "Didoli'r rhan o dan y cyrchwr. Cliciwch, yna pwyswch allwedd; Mae dianc yn ei ddadrwymo.",
|
||||
"horizon.extras.no_ai.tooltip": "Yn cuddio ac yn diffodd pob nodwedd AI: rheolaeth asiant, horizon-ctl a gweinyddwyr MCP. Switsh y lansiwr hefyd.",
|
||||
"horizon.extras.agent_control.tooltip": "Gall eich asiant AI eich hun chwarae'r gêm hon trwy horizon-ctl neu gleient MCP, ar y cyfrifiadur hwn yn unig.",
|
||||
"horizon.extras.discord_presence.tooltip": "Yn dangos Chwarae Horizon ar eich proffil Discord tra bod Discord yn rhedeg: bwydlenni, chwaraewr sengl neu aml-chwaraewr, y dimensiwn a'r amser a chwaraeir. Peidiwch byth ag enw byd na chyfeiriad gweinydd.",
|
||||
"Calibrate...": "Graddnodi...",
|
||||
"Calibrate Anyway...": "Calibro beth bynnag...",
|
||||
"Use Automatic Setup": "Defnyddiwch Gosodiad Awtomatig",
|
||||
"Shortcut: %s": "Llwybr byr: %s",
|
||||
"Next": "Nesaf",
|
||||
"HDR Calibration %s/%s: %s": "Graddnodi HDR %s/%s: %s",
|
||||
"Sets the three below full screen, one test picture at a time.": "Yn gosod y tri isod sgrin lawn, un llun prawf ar y tro.",
|
||||
"A key that opens this screen from the game. Not bound at first.": "Allwedd sy'n agor y sgrin hon o'r gêm. Heb ei rwymo ar y dechrau.",
|
||||
"Your display didn't say how bright it gets: calibrate to set it up.": "Ni ddywedodd eich arddangosfa pa mor llachar y mae'n ei gael: graddnodwch i'w osod.",
|
||||
"Already set up for your display. Only calibrate if HDR looks wrong.": "Eisoes wedi'i osod ar gyfer eich arddangosfa. Calibrowch dim ond os yw HDR yn edrych yn anghywir.",
|
||||
"Puts Peak Brightness and Paper White back to your display's setup.": "Yn rhoi Disgleirdeb Peak a Phapur Gwyn yn ôl i drefniant eich arddangosfa.",
|
||||
"Set up for your display. Leave on Auto unless it looks wrong.": "Gosodwch ar gyfer eich arddangosfa. Gadewch ymlaen Auto oni bai ei fod yn edrych yn anghywir.",
|
||||
"Lower it until the logo just disappears into the black.": "Gostyngwch ef nes bod y logo'n diflannu i'r du.",
|
||||
"Raise it until the logo just disappears into the bright square.": "Codwch ef nes bod y logo'n diflannu i'r sgwâr llachar.",
|
||||
"Make the card a white that's comfortable to look at for a long time, in the light you play in.": "Gwnewch y cerdyn yn wyn sy'n gyfforddus i edrych arno am amser hir, yn y golau rydych chi'n chwarae ynddo.",
|
||||
"horizon.splitscreen.profiles.forget": "Anghofiwch",
|
||||
"horizon.splitscreen.profiles.create": "Creu",
|
||||
"horizon.splitscreen.profiles.you": " - chi",
|
||||
"horizon.splitscreen.profiles.forget_named": "Anghofiwch %s",
|
||||
"horizon.splitscreen.profiles.previous": "Blaenorol",
|
||||
"horizon.splitscreen.profiles.next": "Nesaf",
|
||||
"horizon.splitscreen.profiles.new_button": "Proffil Newydd...",
|
||||
"horizon.splitscreen.profiles.forget_title": "Anghofio proffil?",
|
||||
"horizon.splitscreen.profiles.forget_leaves": "Mae'n gadael rhestr yr enghraifft hon.",
|
||||
"horizon.splitscreen.profiles.forget_kept": "Cedwir cynnydd a gosodiadau'r byd.",
|
||||
"horizon.splitscreen.profiles.new_title": "Proffil Newydd",
|
||||
"horizon.splitscreen.profiles.name_hint": "Enw (3 i 16 llythyren, digid, _)",
|
||||
"horizon.splitscreen.profiles.switch_title": "Newid proffil",
|
||||
"horizon.splitscreen.profiles.offline_note": "Mae proffiliau all-lein yn perthyn i'r achos hwn",
|
||||
"horizon.splitscreen.profiles.move": "Symudwch lle rydych chi'n chwarae",
|
||||
"horizon.splitscreen.profiles.move_place": "Symudwch ble rydych chi'n chwarae: %s",
|
||||
"horizon.friends.title": "Chwarae gyda Ffrindiau",
|
||||
"horizon.friends.hint": "Mae ffrindiau'n gludo'r cod ar ôl botwm Friends y sgrin deitl, yn Direct Connection, neu ar dudalen Chwarae'r lansiwr.",
|
||||
"horizon.friends.copied": "Wedi'i gopïo",
|
||||
"horizon.friends.copy_code": "Copi Cod",
|
||||
"horizon.friends.stop_sharing": "Stopio Rhannu",
|
||||
"horizon.friends.none_yet": "Dim ffrindiau yma eto.",
|
||||
"horizon.friends.here_now": "Yma nawr: %s",
|
||||
"horizon.friends.share_intro": "Rhannwch y byd hwn y tu ôl i god gwahoddiad: mae'n agor i LAN, ac mae ffrindiau ar y rhyngrwyd yn ymuno â'r cod. Nid oes unrhyw weinydd ohonom yn cymryd rhan.",
|
||||
"horizon.friends.start_sharing": "Dechrau Rhannu",
|
||||
"horizon.friends.troubleshooting": "Datrys Problemau...",
|
||||
"horizon.friends.stopped": "Wedi stopio rhannu'r cod gwahoddiad.",
|
||||
"horizon.friends.short_code_changed": "Roedd rhywun yn ceisio cod byr anghywir o hyd, felly fe newidiodd.",
|
||||
"horizon.friends.wrong_code": "Ceisiodd rhywun god anghywir.",
|
||||
"horizon.friends.code_ready": "Mae eich cod gwahoddiad yn barod: Dewislen Gêm, Chwarae gyda Ffrindiau. Copïwch ef a'i anfon at eich ffrindiau.",
|
||||
"horizon.friends.share_failed": "Methu rhannu'r byd: %s",
|
||||
"horizon.friends.finding_route": "Darganfod sut y gall ffrindiau eich cyrraedd…",
|
||||
"horizon.osk.shift": "Turn",
|
||||
"horizon.osk.space": "Gofod",
|
||||
"horizon.osk.delete": "Dileu",
|
||||
"horizon.osk.type": "Math",
|
||||
"horizon.osk.symbols": "Symbolau",
|
||||
"horizon.osk.close": "Cau",
|
||||
"horizon.extras.chat_animation.tooltip": "Mae llinell sgwrsio newydd yn llithro i mewn o'r chwith tra mae'n pylu i mewn, yn lle ymddangos yn gyfan.",
|
||||
"horizon.extras.chat_indicator.tooltip": "Y bar lliw ar ochr chwith llinell sgwrsio.",
|
||||
"horizon.extras.wheel_cycles_settings.tooltip": "Mae'r olwyn sgrolio dros fotwm yn y gosodiadau yn newid ei werth, fel yn y fanila. I ffwrdd, mae'r olwyn yn sgrolio'r rhestr yn unig.",
|
||||
"horizon.extras.pack_browser.tooltip": "Mae Dewis Pecynnau Adnoddau yn cael botwm Ychwanegu sy'n chwilio Modrinth ac yn gosod pecyn yn eich ffolder pecynnau. I ffwrdd, nid yw'r gêm byth yn cysylltu â Modrinth.",
|
||||
"horizon.extras.splitscreen.tooltip": "Mewn byd, gall rheolydd arall ymuno fel chwaraewr newydd: pwyswch A pan fydd yn gofyn, yna dewiswch broffil a ble i chwarae.",
|
||||
"horizon.splitscreen.setup.monitor": "Monitro %s",
|
||||
"horizon.splitscreen.setup.monitor_unknown": "monitor",
|
||||
"horizon.splitscreen.setup.window": "Ffenest %s",
|
||||
"horizon.splitscreen.setup.new_window": "Ffenestr newydd",
|
||||
"horizon.splitscreen.setup.fill_monitor": "Llenwch %s",
|
||||
"horizon.splitscreen.setup.done": "Wedi'i wneud",
|
||||
"horizon.splitscreen.setup.on": "Ar",
|
||||
"horizon.splitscreen.setup.off": "I ffwrdd",
|
||||
"horizon.splitscreen.setup.player": "Chwaraewr %s",
|
||||
"horizon.splitscreen.setup.revert": "Dychwelyd",
|
||||
"horizon.splitscreen.setup.apply": "Ymgeisiwch",
|
||||
"horizon.splitscreen.setup.warning.empty_main": "Nid oes neb yn chwarae yn Ffenestr 1: mae'n cuddio",
|
||||
"horizon.splitscreen.setup.warning.empty_close": "Does neb yn chwarae yn Ffenestr %s: mae'n cau ar Apply",
|
||||
"horizon.splitscreen.setup.warning.empty_new": "Does neb yn chwarae yn Ffenestr %s: ni fydd yn agor",
|
||||
"horizon.splitscreen.setup.warning.on_main": "Mae ffenestr %s yn llenwi monitor Ffenestr 1: mae ei chwaraewyr yn chwarae yn Ffenestr 1",
|
||||
"horizon.splitscreen.setup.warning.unplugged": "Nid yw monitor Window %s wedi'i gysylltu: mae ei chwaraewyr yn chwarae yn Ffenestr 1",
|
||||
"horizon.splitscreen.setup.status.off": "Mae sgrin hollti i ffwrdd.",
|
||||
"horizon.splitscreen.setup.status.enable_hint": "Trowch ef ymlaen, yna pwyswch botwm ar reolwr arall mewn byd.",
|
||||
"horizon.splitscreen.setup.status.join_hint": "Pwyswch A i ymuno a dewis proffil.",
|
||||
"horizon.splitscreen.setup.status.idle": "Sgrîn hollt yn segur",
|
||||
"horizon.splitscreen.setup.status.alone": "Dim chwaraewyr lleol eraill.",
|
||||
"horizon.splitscreen.setup.status.solo_controls": "Nid yw rheolyddion unigol ac adborth rheolwyr wedi newid.",
|
||||
"horizon.splitscreen.setup.window_empty": "Ffenestr %s: gwag",
|
||||
"horizon.splitscreen.setup.note.select": "Cliciwch ar chwaraewr, neu llusgwch ef i ffenestr neu fonitor.",
|
||||
"horizon.splitscreen.setup.note.apply": "Gwnewch gais i chwarae fel hyn, Dychwelwch i ddadwneud.",
|
||||
"horizon.splitscreen.setup.note.place": "Ble ddylai %s chwarae?",
|
||||
"horizon.splitscreen.setup.this_player": "y chwaraewr hwn",
|
||||
"horizon.splitscreen.setup.switch_disabled": "Mae sgrin Hollt yn diffodd unwaith y bydd y lleill wedi gadael (eu dewislen saib).",
|
||||
"horizon.splitscreen.setup.window_place": "Ffenestr %s (%s o %s)",
|
||||
"horizon.splitscreen.setup.names": "Enwau",
|
||||
"horizon.splitscreen.setup.identify": "Adnabod",
|
||||
"horizon.splitscreen.setup.layout.two": "2 yn rhannu: %s",
|
||||
"horizon.splitscreen.setup.layout.three": "3 yn rhannu: %s",
|
||||
"horizon.splitscreen.setup.layout.two.1": "Ochr yn ochr",
|
||||
"horizon.splitscreen.setup.layout.two.2": "Top a gwaelod",
|
||||
"horizon.splitscreen.setup.layout.three.0": "Un llydan ar ei ben",
|
||||
"horizon.splitscreen.setup.layout.three.1": "Un tal ar y chwith",
|
||||
"horizon.splitscreen.setup.layout.three.2": "Ochr yn ochr",
|
||||
"horizon.splitscreen.setup.help.player": "Cliciwch neu llusgwch %s i'w symud.",
|
||||
"horizon.splitscreen.setup.help.layout_auto": "%s (ochr yn ochr pan fydd y ffenestr yn llydan). Pwyswch i newid.",
|
||||
"horizon.splitscreen.setup.help.layout": "%s. Pwyswch i newid.",
|
||||
"horizon.splitscreen.setup.help.switch": "Sgrîn hollti ar gyfer y cyfrifiadur hwn, ymlaen neu i ffwrdd.",
|
||||
"horizon.splitscreen.setup.help.identify": "Mae golygfa pob chwaraewr yn dangos ym mha ffenestr y mae.",
|
||||
"horizon.splitscreen.setup.help.names": "Enw pob chwaraewr yng nghornel eu golygfa.",
|
||||
"horizon.splitscreen.setup.help.revert": "Dad-wneud y newidiadau nas gweithredwyd eto.",
|
||||
"horizon.splitscreen.setup.help.apply": "Chwaraewch y ffordd mae'r map yn ei ddangos.",
|
||||
"horizon.splitscreen.setup.help.unchanged": "Dim byd wedi newid eto.",
|
||||
"horizon.splitscreen.setup.give_up_pad": "Pad rhoi'r gorau iddi",
|
||||
"horizon.splitscreen.prompt.controller_connected": "Rheolwr wedi'i gysylltu",
|
||||
"horizon.splitscreen.prompt.controller_disconnected": "Rheolydd wedi'i ddatgysylltu",
|
||||
"horizon.splitscreen.prompt.controller_disconnected.hint": "Ailgysylltu ef, neu gwasgwch botwm ar un arall",
|
||||
"horizon.splitscreen.prompt.join.one": "Mae %s eisiau ymuno",
|
||||
"horizon.splitscreen.prompt.join.many": "%s rheolwyr eisiau ymuno",
|
||||
"horizon.splitscreen.prompt.join.yes": "Ymuno",
|
||||
"horizon.splitscreen.prompt.join.as_p1": "Chwarae fel P1",
|
||||
"horizon.splitscreen.prompt.join.no": "Nac ydw",
|
||||
"horizon.splitscreen.prompt.lost": "%s: rheolydd wedi'i ddatgysylltu",
|
||||
"horizon.splitscreen.prompt.lost.use_another": "Defnyddiwch un arall",
|
||||
"horizon.splitscreen.prompt.lost.leave": "Gadael",
|
||||
"horizon.splitscreen.setup.help.give_up_pad": "Mae eich rheolydd yn rhoi'r gorau i'ch gyrru a chynigir iddo ymuno (A).",
|
||||
"horizon.splitscreen.setup.note.held_at": "%s i %s: Mae A yn ei ollwng yma, mae B yn ei roi yn ôl.",
|
||||
"horizon.splitscreen.setup.note.held": "%s codi: chwith/dde yn codi ble, A yn disgyn, B yn ei roi yn ôl.",
|
||||
"Hides models behind opaque blocks. Async checks off-thread; entities tick.": "Yn cuddio modelau y tu ôl i flociau afloyw. Mae Async yn gwirio oddi ar yr edau; endidau tic.",
|
||||
"Block Entities": "Endidau Bloc",
|
||||
"Shulker Boxes": "Blychau Shulker",
|
||||
"Reuses settled boxes; lid movement stays animated.": "Yn ailddefnyddio blychau sefydlog; symudiad caead yn aros yn animeiddiedig.",
|
||||
"Signs": "Arwyddion",
|
||||
"Reuses sign text until text, light, or font changes.": "Yn ailddefnyddio testun arwyddo nes bod testun, golau neu ffont yn newid.",
|
||||
"Decorated Pots": "Potiau Addurnedig",
|
||||
"Reuses still pots; break wobble and sherd changes redraw.": "Yn ailddefnyddio potiau llonydd; torri siglo ac ail-lunio newidiadau sherd.",
|
||||
"Bells": "Clychau",
|
||||
"Reuses still bells; ringing stays animated.": "Yn ailddefnyddio clychau o hyd; mae canu yn aros yn animeiddiedig.",
|
||||
"Chests": "Cistiau",
|
||||
"Reuses closed chests; moving lids stay animated.": "Yn ailddefnyddio cistiau caeedig; symud caeadau aros yn animeiddiedig.",
|
||||
"Banners": "Baneri",
|
||||
"Reuses poles; flags and pattern layers still update.": "Yn ailddefnyddio polion; baneri a haenau patrwm yn dal i ddiweddaru.",
|
||||
"Copper Golem Statues": "Cerfluniau Golem Copr",
|
||||
"Reuses statue geometry until its block state changes.": "Yn ailddefnyddio geometreg cerflun nes bod ei gyflwr bloc yn newid.",
|
||||
"Leaf Culling": "Difa Dail",
|
||||
"Every leaf face. Vanilla's fancy leaves.": "Wyneb pob deilen. Dail ffansi fanila.",
|
||||
"Distant Plant Dither": "Dither Planhigion Pell",
|
||||
"Keeps fine plants in high-res packs from fading far away.": "Yn cadw planhigion mân mewn pecynnau cydraniad uchel rhag pylu ymhell i ffwrdd.",
|
||||
"Screenshot Quality": "Ansawdd Sgrinlun",
|
||||
"F2 screenshots at this many times the game's resolution. Higher takes longer.": "Sgrinluniau F2 ar hyn o bryd lawer o benderfyniad y gêm. Mae uwch yn cymryd mwy o amser.",
|
||||
"Frame Generation": "Cynhyrchu Ffrâm",
|
||||
"Shows a made-up frame between each two real ones: smoother, a little more lag.": "Yn dangos ffrâm wedi'i gwneud i fyny rhwng pob dau go iawn: llyfnach, ychydig yn fwy oedi.",
|
||||
"Shadow Cache": "Cache Cysgod",
|
||||
"Reuses the pack shadow map when sun, view and world match. Off by default.": "Yn ailddefnyddio'r map cysgodion pecyn pan fydd yr haul, yr olygfa a'r byd yn cyd-fynd. Wedi'i ddiffodd yn ddiofyn.",
|
||||
"Find BlueMap": "Dewch o hyd i BlueMap",
|
||||
"On servers, finds their BlueMap web map for far terrain. Next join.": "Ar weinyddion, yn dod o hyd i'w map gwe BlueMap ar gyfer tir pell. Ymunwch nesaf.",
|
||||
"BlueMap Radius": "Radiws BlueMap",
|
||||
"How far around you BlueMap tiles are downloaded. Next join.": "Pa mor bell o'ch cwmpas y mae teils BlueMap yn cael eu llwytho i lawr. Ymunwch nesaf.",
|
||||
"Synchronous": "Cydamserol",
|
||||
"Solid Aggressive": "Solid Ymosodol",
|
||||
"Hollow": "gwag",
|
||||
"Leaves fully inside a canopy draw solid: fewer see-through layers.": "Mae'r dail yn gyfan gwbl y tu mewn i ganopi yn tynnu'n solet: llai o haenau trwodd.",
|
||||
"Leaves with one open side draw solid too: faster, chunkier edges.": "Mae dail gydag un ochr agored yn tynnu'n solet hefyd: ymylon cyflymach, mwy trwchus.",
|
||||
"Drops faces between leaves: faster, but gaps look through.": "Wynebau diferion rhwng dail: yn gyflymach, ond bylchau yn edrych drwodd.",
|
||||
"Hotbar: Previous Slot": "Hotbar: Slot Blaenorol",
|
||||
"Hotbar: Next Slot": "Hotbar: Slot Nesaf",
|
||||
"horizon.agent.connected.one": "Cysylltiedig: 1 cysylltiad asiant",
|
||||
"horizon.agent.connected.many": "Cysylltiedig: %s cysylltiadau asiant",
|
||||
"horizon.agent.connected.one_ago": "Cysylltiedig: 1 cysylltiad asiant, gorchymyn diwethaf %s s yn ôl",
|
||||
"horizon.agent.connected.many_ago": "Cysylltiedig: %s cysylltiadau asiant, gorchymyn diwethaf %s s yn ôl",
|
||||
"horizon.agent.waiting": "Aros am asiant.",
|
||||
"horizon.agent.off": "I ffwrdd: ni all asiantau gyrraedd y gêm hon.",
|
||||
"horizon.agent.session_opened": "Agorwyd ar gyfer y sesiwn hon gan y rhaglen a ddechreuodd y gêm.",
|
||||
"horizon.agent.socket": "Soced: %s (copïwch y manylion ar gyfer ei lwybr llawn)",
|
||||
"horizon.agent.local_only": "Lleol yn unig: asiantau ar y cyfrifiadur hwn, byth y rhwydwaith.",
|
||||
"Hides models behind opaque blocks. Entities update. Off with custom packs.": "Yn cuddio modelau y tu ôl i flociau afloyw. Diweddariad endidau. I ffwrdd â phecynnau arferol.",
|
||||
"horizon.extras.repro_keys": "Recordio llwybrau byr",
|
||||
"horizon.extras.repro_keys.tooltip": "Mae F3+R yn cychwyn neu'n stopio recordiad repro ac mae F3+E yn ysgrifennu ei fwndel. Wedi'i ddiffodd yn ddiofyn: mae recordiad yn copïo'r byd.",
|
||||
"horizon.agent.record_session": "Dechrau Sesiwn Recordio",
|
||||
"horizon.agent.record_stop": "Sesiwn Stopio Recordio",
|
||||
"horizon.agent.export_repro": "Bwndel Repro Allforio",
|
||||
"horizon.repro.started": "Dechreuwyd recordio; Mae F3+R yn ei stopio ac yn ysgrifennu'r bwndel.",
|
||||
"horizon.repro.stopped": "Stopio recordio: %s",
|
||||
"horizon.repro.bundle": "Bwndel repro: %s",
|
||||
"horizon.repro.error": "Atgynhyrchiad: %s",
|
||||
"horizon.repro.no_recording": "Nid oes recordiad i'w allforio eto.",
|
||||
"horizon.repro.replay_started": "Ailchwarae wedi dechrau: %s",
|
||||
"horizon.pack.addInfo": "Ychwanegu pecyn adnoddau gan Modrinth",
|
||||
"horizon.pack.addWorking": "Wrthi'n holi Modrinth...",
|
||||
"horizon.pack.addNone": "Heb ganfod pecynnau adnoddau",
|
||||
"horizon.pack.addTitle": "Ychwanegu Pecyn Adnoddau",
|
||||
"horizon.pack.install": "Gosod",
|
||||
"horizon.pack.installing": "Gosod",
|
||||
"horizon.pack.installed": "Wedi'i osod",
|
||||
"horizon.pack.search": "Chwiliwch",
|
||||
"horizon.pack.searchHint": "Chwilio Modrinth...",
|
||||
"horizon.pack.filters": "Hidlau",
|
||||
"horizon.pack.filter.realistic": "Realistig",
|
||||
"horizon.pack.filter.simplistic": "Syml",
|
||||
"horizon.pack.filter.vanillaLike": "Fel fanila",
|
||||
"horizon.pack.addFailed": "Ni ellid ychwanegu'r pecyn: %s",
|
||||
"horizon.extras.cosmetics_mine": "Fy colur",
|
||||
"horizon.extras.cosmetics_mine.tooltip": "Cudd: mae pob chwaraewr Horizon yn eich gweld heb eich colur, fe wnaethoch chi gynnwys. Yr un switsh â Wardrob y lansiwr.",
|
||||
"horizon.extras.cosmetics_others": "Colur chwaraewyr eraill",
|
||||
"horizon.extras.cosmetics_others.tooltip": "Beth mae chwaraewyr Horizon eraill yn ei wisgo: popeth, dim ond eu steil tag enw, neu ddim byd. Yn gudd, nid yw'r gêm byth yn gofyn beth maen nhw'n ei wisgo.",
|
||||
"horizon.extras.cosmetics_auras": "Auras a llwybrau eraill",
|
||||
"horizon.extras.cosmetics_auras.tooltip": "Auras a llwybrau mae chwaraewyr eraill yn eu gwisgo. Wedi'i ddiffodd yn ddiofyn.",
|
||||
"horizon.extras.cosmetics.shown": "Dangosir",
|
||||
"horizon.extras.cosmetics.hidden": "Cudd",
|
||||
"horizon.extras.cosmetics.name_tags": "Tagiau enw yn unig"
|
||||
}
|
||||
@@ -8,11 +8,9 @@
|
||||
"horizon.options.move_deadzone": "Dødzone for bevægelse",
|
||||
"horizon.options.look_deadzone": "Dødzone for kig",
|
||||
"horizon.options.button_glyphs": "Knap Glyfer",
|
||||
"horizon.options.menu_navigation": "Menu navigation",
|
||||
"horizon.options.on_screen_keyboard": "Skærmtastatur",
|
||||
"horizon.options.chat_delay": "Chatforsinkelse",
|
||||
"horizon.options.lightbar.health": "Sundhed",
|
||||
"horizon.options.menu_focus": "Fokus",
|
||||
"horizon.options.keyboard.steam": "Damp",
|
||||
"horizon.options.unavailable": "Denne funktion er endnu ikke tilgængelig i Horizon.",
|
||||
"horizon.options.search": "Søgeindstillinger...",
|
||||
@@ -154,7 +152,7 @@
|
||||
"Cloud layer: off, flat (fast) or 3D (fancy).": "Skylag: slukket, fladt (hurtigt) eller 3D (fancy).",
|
||||
"How far clouds reach, in chunks.": "Hvor langt skyer når, i bidder.",
|
||||
"Draws the sky, sun, moon and stars.": "Tegner himmel, sol, måne og stjerner.",
|
||||
"Distance fog. Off shows the edge of the loaded world.": "Afstandståge. Off viser kanten af den belastede verden.",
|
||||
"Distance fog. Off shows the edge of the loaded world.": "Afstandståge. Off viser kanten af den belastede verden.",
|
||||
"Draws rain and snow.": "Tegner regn og sne.",
|
||||
"How far rain and snow fall around you.": "Hvor langt regn og sne falder omkring dig.",
|
||||
"How many particles effects spawn.": "Hvor mange partikler effekter gyder.",
|
||||
@@ -287,7 +285,7 @@
|
||||
"horizon.friends.stop_sharing": "Stop deling",
|
||||
"horizon.friends.none_yet": "Ingen venner her endnu.",
|
||||
"horizon.friends.here_now": "Her nu: %s",
|
||||
"horizon.friends.share_intro": "Del denne verden bag en invitationskode: den åbner til LAN, og venner på internettet deltager med koden. Ingen af vores servere er involveret.",
|
||||
"horizon.friends.share_intro": "Del denne verden bag en invitationskode: den åbner til LAN, og venner på internettet deltager med koden. Ingen af vores servere er involveret.",
|
||||
"horizon.friends.start_sharing": "Begynd at dele",
|
||||
"horizon.friends.troubleshooting": "Fejlfinding...",
|
||||
"horizon.friends.stopped": "Stoppet med at dele invitationskoden.",
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
"horizon.options.move_deadzone": "Totzone der Bewegung",
|
||||
"horizon.options.look_deadzone": "Totzone des Blicks",
|
||||
"horizon.options.button_glyphs": "Tastensymbole",
|
||||
"horizon.options.menu_navigation": "Menünavigation",
|
||||
"horizon.options.on_screen_keyboard": "Bildschirmtastatur",
|
||||
"horizon.options.chat_delay": "Chatverzögerung",
|
||||
"horizon.options.lightbar.health": "Gesundheit",
|
||||
@@ -20,8 +19,6 @@
|
||||
"horizon.options.glyphs.xbox": "Xbox",
|
||||
"horizon.options.glyphs.playstation": "PlayStation",
|
||||
"horizon.options.glyphs.nintendo": "Nintendo",
|
||||
"horizon.options.menu_focus": "Fokus",
|
||||
"horizon.options.menu_pointer": "Zeiger",
|
||||
"horizon.options.keyboard.auto": "Auto",
|
||||
"horizon.options.keyboard.horizon": "Horizon",
|
||||
"horizon.options.keyboard.steam": "Steam",
|
||||
|
||||
@@ -9,14 +9,11 @@
|
||||
"horizon.options.move_deadzone": "Νεκρή ζώνη κίνησης",
|
||||
"horizon.options.look_deadzone": "Νεκρή ζώνη κάμερας",
|
||||
"horizon.options.button_glyphs": "Γλυφικά κουμπιών",
|
||||
"horizon.options.menu_navigation": "Πλοήγηση μενού",
|
||||
"horizon.options.on_screen_keyboard": "Πληκτρολόγιο οθόνης",
|
||||
"horizon.options.chat_delay": "Καθυστέρηση συνομιλίας",
|
||||
"horizon.options.lightbar.health": "Υγεία",
|
||||
"horizon.options.lightbar.dimension": "Διάσταση",
|
||||
"horizon.options.glyphs.auto": "Αυτόματο",
|
||||
"horizon.options.menu_focus": "Εστίαση",
|
||||
"horizon.options.menu_pointer": "Δείκτης",
|
||||
"horizon.options.keyboard.auto": "Αυτόματο",
|
||||
"horizon.options.unavailable": "Αυτή η δυνατότητα δεν είναι ακόμη διαθέσιμη στο Horizon.",
|
||||
"horizon.options.search": "Ρυθμίσεις αναζήτησης...",
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
"horizon.options.move_deadzone": "Move Deadzone",
|
||||
"horizon.options.look_deadzone": "Look Deadzone",
|
||||
"horizon.options.button_glyphs": "Button Glyphs",
|
||||
"horizon.options.menu_navigation": "Menu Navigation",
|
||||
"horizon.options.on_screen_keyboard": "On-Screen Keyboard",
|
||||
"horizon.options.chat_delay": "Chat Delay",
|
||||
"horizon.options.lightbar.health": "Health",
|
||||
@@ -20,8 +19,6 @@
|
||||
"horizon.options.glyphs.xbox": "Xbox",
|
||||
"horizon.options.glyphs.playstation": "PlayStation",
|
||||
"horizon.options.glyphs.nintendo": "Nintendo",
|
||||
"horizon.options.menu_focus": "Focus",
|
||||
"horizon.options.menu_pointer": "Pointer",
|
||||
"horizon.options.keyboard.auto": "Auto",
|
||||
"horizon.options.keyboard.horizon": "Horizon",
|
||||
"horizon.options.keyboard.steam": "Steam",
|
||||
@@ -522,5 +519,10 @@
|
||||
"horizon.extras.cosmetics_auras.tooltip": "Auras and trails other players wear. Off by default.",
|
||||
"horizon.extras.cosmetics.shown": "Shown",
|
||||
"horizon.extras.cosmetics.hidden": "Hidden",
|
||||
"horizon.extras.cosmetics.name_tags": "Name tags only"
|
||||
"horizon.extras.cosmetics.name_tags": "Name tags only",
|
||||
"horizon.options.pointer_speed": "Menu Pointer Speed",
|
||||
"horizon.options.scroll_speed": "Menu Scroll Speed",
|
||||
"horizon.options.repeat_delay": "Navigation Repeat Delay",
|
||||
"horizon.options.repeat_interval": "Navigation Repeat Interval",
|
||||
"horizon.options.milliseconds": "%s ms"
|
||||
}
|
||||
@@ -0,0 +1,475 @@
|
||||
{
|
||||
"horizon.options.controller": "Regilo",
|
||||
"horizon.options.three_d_skin_layers": "3D Haŭtaj Tavoloj",
|
||||
"horizon.options.vibration": "Vibro",
|
||||
"horizon.options.adaptive_triggers": "Adaptigaj ellasiloj",
|
||||
"horizon.options.lightbar": "Lumbreto",
|
||||
"horizon.options.look_sensitivity": "Rigarda sentemo",
|
||||
"horizon.options.invert_x": "Inversa rigardo X",
|
||||
"horizon.options.invert_y": "Inversa rigardo Y",
|
||||
"horizon.options.sneak_button": "Ŝtelira Butono",
|
||||
"horizon.options.move_deadzone": "Mova mortzono",
|
||||
"horizon.options.look_deadzone": "Rigarda mortzono",
|
||||
"horizon.options.button_glyphs": "Butonaj Glifoj",
|
||||
"horizon.options.on_screen_keyboard": "Surekrana Klavaro",
|
||||
"horizon.options.chat_delay": "Babilado Prokrasto",
|
||||
"horizon.options.lightbar.health": "Sano",
|
||||
"horizon.options.lightbar.dimension": "Dimensio",
|
||||
"horizon.options.glyphs.auto": "Aŭtomate",
|
||||
"horizon.options.keyboard.auto": "Aŭtomate",
|
||||
"horizon.options.unavailable": "Ĉi tiu funkcio ankoraŭ ne disponeblas en Horizon.",
|
||||
"horizon.options.search": "Serĉaj agordoj...",
|
||||
"horizon.pages.shader_packs": "Shader-Pakoj",
|
||||
"horizon.pages.shader_options": "Shader Opcioj",
|
||||
"horizon.pages.controller": "Agordoj de la regilo",
|
||||
"horizon.pages.controller_binds": "Regilo Ligas",
|
||||
"horizon.pages.extras": "Horizon Kromaĵoj",
|
||||
"horizon.pages.settings": "Horizon Agordoj",
|
||||
"horizon.pages.agent": "AI-agento",
|
||||
"horizon.split.leave": "Foriru",
|
||||
"horizon.pages.split_settings": "Splitekranaj Agordoj",
|
||||
"horizon.pages.split_profiles": "Kiu ludas?",
|
||||
"horizon.pages.split_setup": "Agordo de Splitekrano",
|
||||
"horizon.pages.music": "Muziko",
|
||||
"horizon.pages.music.menu": "Menuo",
|
||||
"horizon.pages.music.overworld": "Supermondo",
|
||||
"horizon.pages.music.creative": "Kreiva",
|
||||
"horizon.pages.music.underwater": "Subakve",
|
||||
"horizon.pages.music.end": "La Fino",
|
||||
"horizon.pages.music.boss": "Estro",
|
||||
"horizon.pages.music.credits": "Kreditoj",
|
||||
"horizon.pages.music.overworld_biomes": "Supermondaj biomoj",
|
||||
"horizon.pages.music.nether_biomes": "Malsupraj biomoj",
|
||||
"horizon.pages.music.end_biomes": "Fini biomojn",
|
||||
"horizon.pages.music.other": "Alia muziko",
|
||||
"horizon.pages.music.empty": "Neniuj muzikoj: la sonoj de la ludo ne estas ŝarĝitaj.",
|
||||
"horizon.pages.music.tooltip": "La enkonstruitaj spuroj, laŭ situacio: ludu unu nun, aŭ malŝaltu iun ajn por ke la ludo ĉesu elekti ĝin.",
|
||||
"horizon.pages.settings.tooltip": "La propraj agordoj de Horizon: grafikaĵoj, regiloj, kromaĵoj kaj modoj.",
|
||||
"horizon.pages.graphics.tooltip": "Grafikoj, simple: ĉiu agordo diras, kion ĝi kostas.",
|
||||
"horizon.pages.graphics_advanced.tooltip": "Ĉiu grafika agordo, inkluzivita Horizon, kun tio, kion ĉiu kostas.",
|
||||
"horizon.pages.controller.tooltip": "Regiloj: iliaj butonoj, bastonoj, vibro kaj menua navigado.",
|
||||
"horizon.pages.extras.tooltip": "Laŭvolaj aldonoj, ĉiuj malŝaltitaj defaŭlte: la ludo restas vanilo ĝis vi ŝaltas unu.",
|
||||
"horizon.pages.agent.tooltip": "Lasu vian propran AI-agenton ludi: horizon-ctl kaj MCP-klientoj sur ĉi tiu komputilo.",
|
||||
"horizon.pages.split_profiles.tooltip": "Kiu ludas: profilo konservita en ĉi tiu luddosierujo.",
|
||||
"horizon.pages.split_setup.tooltip": "La fenestroj kaj monitoroj, kaj kiu ludas kie.",
|
||||
"horizon.pages.shader_packs.tooltip": "Shader-pakaĵoj el la dosierujo shaderpacks: la propra Horizon kaj tiuj en la ombraj/formato. Oni kuras samtempe.",
|
||||
"horizon.pages.mods.tooltip": "Modifoj faritaj por Horizon, el la dosierujo horizon-mods. Ĉiu kuras en sablokesto kaj restas malŝaltita ĝis vi ŝaltas ĝin.",
|
||||
"horizon.pages.open.graphics": "Grafikoj...",
|
||||
"horizon.pages.open.graphics_advanced": "Altnivelaj Grafikoj...",
|
||||
"horizon.pages.open.shader_packs": "Shader-Pakoj...",
|
||||
"horizon.pages.open.controller": "Agordoj de regilo...",
|
||||
"horizon.pages.open.split_setup": "Splitekrano...",
|
||||
"horizon.pages.open.extras": "Kromaĵoj...",
|
||||
"horizon.pages.open.mods": "Modifoj...",
|
||||
"horizon.pages.open.agent": "AI-agento...",
|
||||
"horizon.pages.open.horizon_graphics": "Horizon Grafikoj...",
|
||||
"horizon.pages.open.controller_binds": "Regilo ligas...",
|
||||
"horizon.pages.open.horizon_settings": "Horizon Agordoj...",
|
||||
"horizon.pages.open.music": "Muziko...",
|
||||
"horizon.mods.empty": "Neniuj modoj: metu .hmod dosierojn en la dosierujon horizon-mods",
|
||||
"horizon.mods.stopped": " (Haltis)",
|
||||
"horizon.mods.not_built": " (Ne konstruita)",
|
||||
"horizon.mods.settings": "Agordoj",
|
||||
"horizon.mods.in_world": " (lasu la mondon ŝanĝi)",
|
||||
"horizon.mods.open_folder": "Malfermu Mod-dosierujon",
|
||||
"horizon.shader_packs.empty": "Neniuj ombraj pakoj: metu ilin en la dosierujon de ombraj pakoj",
|
||||
"horizon.shader_options.open": "Ombrilaj Opcioj...",
|
||||
"horizon.shader_options.profile": "Profilo",
|
||||
"horizon.shader_options.loading": "Legante la opciojn de la ombra pako...",
|
||||
"horizon.agent.copy_details": "Kopiu Detalojn pri Konekto",
|
||||
"horizon.multiplayer.join": "Aliĝu",
|
||||
"horizon.multiplayer.cancel_reconnecting": "Nuligi Rekonekti",
|
||||
"horizon.multiplayer.join_friend": "Aliĝu al Amiko",
|
||||
"horizon.multiplayer.invite_code": "Inviti Kodon",
|
||||
"horizon.multiplayer.relay": "Relajso (laŭvola)",
|
||||
"Preset": "Antaŭdifinita",
|
||||
"LOD Distance": "LOD Distanco",
|
||||
"Far Detail": "Malproksima Detalo",
|
||||
"Cave Culling": "Kavernhakado",
|
||||
"Entity Culling": "Ento Culling",
|
||||
"Chunk Updates": "Chunk Ĝisdatigoj",
|
||||
"Upload Budget": "Alŝutu Buĝeton",
|
||||
"Sky": "Ĉielo",
|
||||
"Fog": "Nebulo",
|
||||
"Weather": "Vetero",
|
||||
"Animated Textures": "Viglaj Teksturoj",
|
||||
"Present Mode": "Nuna Reĝimo",
|
||||
"Frame Pacing": "Kadra Paŝado",
|
||||
"Worker Threads": "Laboristaj Fadenoj",
|
||||
"Resolution Scale": "Rezolucia Skalo",
|
||||
"Anti-aliasing": "Kontraŭaliasing",
|
||||
"Upscaling": "Altskalo",
|
||||
"Paper White": "Papero Blanka",
|
||||
"Peak Brightness": "Pinta Brilo",
|
||||
"Black Level": "Nigra Nivelo",
|
||||
"UI Brightness": "UI Brilo",
|
||||
"Battery Mode": "Bateria Reĝimo",
|
||||
"Graphics API": "Grafika API",
|
||||
"Translucent Batching": "Travidebla Batching",
|
||||
"Performance Overlay": "Efikeco Overlay",
|
||||
"Full Detail Distance": "Plena Detalo Distanco",
|
||||
"Off": "Malŝaltita",
|
||||
"Unlimited": "Senlima",
|
||||
"Auto": "Aŭtomate",
|
||||
"Custom": "Kutimo",
|
||||
"Performance": "Agado",
|
||||
"Balanced": "Ekvilibrata",
|
||||
"Quality": "Kvalito",
|
||||
"Native": "Denaska",
|
||||
"Full": "Plena",
|
||||
"Reduced": "Reduktita",
|
||||
"Efficient": "Efika",
|
||||
"Precise": "Precize",
|
||||
"Auto (VSync)": "Aŭtomata (VSync)",
|
||||
"Mailbox": "Leterkesto",
|
||||
"Immediate": "Tuj",
|
||||
"FPS and Graph": "FPS kaj Grafiko",
|
||||
"No cost": "Sen kosto",
|
||||
"Low cost": "Malalta kosto",
|
||||
"Medium cost": "Meza kosto",
|
||||
"High cost": "Alta kosto",
|
||||
"Saves time": "Ŝparas tempon",
|
||||
"Graphics": "Grafikoj",
|
||||
"Done": "Farita",
|
||||
"This feature is not yet available in Horizon.": "Ĉi tiu funkcio ankoraŭ ne disponeblas en Horizon.",
|
||||
"Your display or system doesn't offer HDR output.": "Via ekrano aŭ sistemo ne ofertas HDR-eligon.",
|
||||
"Turn HDR on to use it.": "Ŝaltu HDR por uzi ĝin.",
|
||||
"Your GPU or graphics API doesn't support it.": "Via GPU aŭ grafika API ne subtenas ĝin.",
|
||||
"%s chunks": "%s pecoj",
|
||||
"%s per frame": "%s per kadro",
|
||||
"%s MiB/frame": "%s MiB/kadro",
|
||||
"%s KiB/frame": "%s KiB/kadro",
|
||||
"Auto (%s)": "Aŭtomata (%s)",
|
||||
"Full-detail terrain range. LOD Distance can extend local worlds farther.": "Plendetala terena gamo. LOD Distanco povas etendi lokajn mondojn pli for.",
|
||||
"Coarse distant terrain in local worlds. Integrated GPUs stop at 128 chunks.": "Kruda malproksima tereno en lokaj mondoj. Integritaj GPUoj ĉesas ĉe 128 pecoj.",
|
||||
"Reduced draws far terrain coarser: faster on this integrated GPU.": "Reduktitaj tiradoj multe pli krudaj: pli rapide sur ĉi tiu integra GPU.",
|
||||
"Reduced draws far terrain coarser, for GPUs it slows down.": "Reduktita tirado multe pli kruda, por GPU-oj ĝi malrapidiĝas.",
|
||||
"Field of view. Wider shows more terrain at once.": "Vidkampo. Pli larĝa montras pli da tereno samtempe.",
|
||||
"Caps frames per second; a cap saves power and heat.": "Ĉapaj kadroj por sekundo; ĉapo ŝparas potencon kaj varmon.",
|
||||
"Waits for the display's refresh: no tearing, a little latency.": "Atendas la refreŝigon de la ekrano: neniu ŝirado, iom da latenco.",
|
||||
"Size of menus and the HUD.": "Grandeco de menuoj kaj la HUD.",
|
||||
"Sets the options below together. Changing one makes it Custom.": "Kunigas la eblojn sube. Ŝanĝi unu faras ĝin Propra.",
|
||||
"Lava, fire and sunlight shine brighter than white. Needs an HDR display.": "Lafo, fajro kaj sunlumo brilas pli hele ol blanka. Bezonas HDR-ekranon.",
|
||||
"Your display's darkest black. 0 for OLED; LCDs glow a little.": "Via ekrano estas plej malhela nigra. 0 por OLED; LCD-oj brilas iomete.",
|
||||
"How bright highlights get. Auto: the peak your system reports.": "Kiel brilaj brilaĵoj ricevas. Aŭtomata: la pinto kiun via sistemo raportas.",
|
||||
"How bright white paper and menus look. Auto: your desktop's white.": "Kiel brile blankaj paperoj kaj menuoj aspektas. Aŭtomata: via labortablo estas blanka.",
|
||||
"How bright the HUD and menus are, against paper white.": "Kiel brilaj la HUD kaj menuoj estas, kontraŭ papera blanka.",
|
||||
"How far mobs, crops and machines keep working. CPU time.": "Kiom malproksime amasoj, kultivaĵoj kaj maŝinoj daŭre funkcias. CPU-tempo.",
|
||||
"How far away mobs and items are drawn, as a share of normal.": "Kiom malproksime amasoj kaj eroj estas tiritaj, kiel parto de normalo.",
|
||||
"Skips terrain hidden behind closed sections. Off costs a lot.": "Saltas terenon kaŝitan malantaŭ fermitaj sekcioj. For kostas multe.",
|
||||
"Hides entities behind opaque blocks.": "Kaŝas estaĵojn malantaŭ maldiafanaj blokoj.",
|
||||
"No entity occlusion culling.": "Neniu ento-okludo-eliminado.",
|
||||
"CPU occlusion test runs this frame.": "CPU-okludtesto kuras ĉi tiun kadron.",
|
||||
"Occlusion checks run on a worker thread.": "Fermokontroloj funkcias sur laborfadeno.",
|
||||
"Meshed sections uploaded per frame. Lower is smoother while loading.": "Reksitaj sekcioj alŝutitaj per kadro. Malsupra estas pli glata dum ŝarĝo.",
|
||||
"Soft shadows in corners. Costs chunk building time only.": "Mildaj ombroj en anguloj. Kostas nur ioman konstruan tempon.",
|
||||
"Smaller copies of block textures for distant terrain: less shimmer.": "Pli malgrandaj kopioj de blokaj teksturoj por malproksima tereno: malpli brilo.",
|
||||
"Blends grass and water colours across biomes when building chunks.": "Miksas herbon kaj akvokolorojn tra biomoj dum konstruado de pecoj.",
|
||||
"Cloud layer: off, flat (fast) or 3D (fancy).": "Nuba tavolo: malŝaltita, plata (rapida) aŭ 3D (fantazia).",
|
||||
"How far clouds reach, in chunks.": "Kiom malproksime atingas nuboj, en pecoj.",
|
||||
"Draws the sky, sun, moon and stars.": "Desegnas la ĉielon, sunon, lunon kaj stelojn.",
|
||||
"Distance fog. Off shows the edge of the loaded world.": "Distanca nebulo. Off montras la randon de la ŝarĝita mondo.",
|
||||
"Draws rain and snow.": "Desegnas pluvon kaj neĝon.",
|
||||
"How far rain and snow fall around you.": "Kiom longe pluvo kaj neĝo falas ĉirkaŭ vi.",
|
||||
"How many particles effects spawn.": "Kiom da partikloj generas.",
|
||||
"Round shadows under mobs and items.": "Rondaj ombroj sub homamasoj kaj aĵoj.",
|
||||
"Leaves with see-through gaps. Off draws them solid.": "Folioj kun travideblaj interspacoj. Off tiras ilin solidaj.",
|
||||
"Sorts water and glass more exactly behind each other.": "Ordigas akvon kaj glason pli precize unu malantaŭ la alia.",
|
||||
"Which chunk rebuilds wait for the frame: none, nearby or yours.": "Kiu peco rekonstruas atendas la kadron: neniu, proksime aŭ via.",
|
||||
"Animates water, lava, fire and other moving textures.": "Animas akvon, lafon, fajron kaj aliajn moviĝantajn teksturojn.",
|
||||
"World pixels per screen pixel. Below 100% is faster on the GPU.": "Mondaj pikseloj per ekranpikselo. Sub 100% estas pli rapida sur la GPU.",
|
||||
"Smooths jagged edges. FXAA: softer. TAA: smoothest, moving things may trail.": "Glatigas dentitajn randojn. FXAA: pli mola. TAA: plej glate, moviĝantaj aferoj povas spuri.",
|
||||
"Renders the world smaller and rebuilds it with TAA. Faster, softer.": "Malgrandigas la mondon kaj rekonstruas ĝin per TAA. Faster, pli mola.",
|
||||
"HDR output on an HDR display: lava, fire and sunlight shine brighter.": "HDR-eligo sur HDR-ekrano: lafo, fajro kaj sunlumo brilas pli hele.",
|
||||
"How frames reach the screen while VSync is off.": "Kiel kadroj atingas la ekranon dum VSync estas malŝaltita.",
|
||||
"Efficient sleeps until the next frame; Precise spins, like vanilla.": "Efika dormas ĝis la sekva kadro; Precizaj turnoj, kiel vanilo.",
|
||||
"Fills the screen (borderless).": "Plenigas la ekranon (senborda).",
|
||||
"Brightens dark places.": "Heligas malhelajn lokojn.",
|
||||
"Lowers the frame rate when minimised, or idle too.": "Malaltigas la framfrekvencon kiam minimumigita, aŭ neaktiva ankaŭ.",
|
||||
"Sways the view while walking.": "Ŝancelas la vidon dum marŝado.",
|
||||
"Fades newly loaded chunks in.": "Fadas lastatempe ŝarĝitajn pecojn.",
|
||||
"Darkens the screen's edges.": "Malheligas la randojn de la ekrano.",
|
||||
"Shows when the world saves.": "Montras kiam la mondo savas.",
|
||||
"Shows attack cooldown.": "Montras atakan malvarmiĝon.",
|
||||
"60 FPS cap (30 in menus or unfocused), half the workers: less power.": "60 FPS-ĉapo (30 en menuoj aŭ nefokusitaj), duono de la laboristoj: malpli da potenco.",
|
||||
"Threads that generate, light and mesh chunks. Next start.": "Fadenoj kiuj generas, malpezajn kaj maŝpecojn. Sekva komenco.",
|
||||
"Vulkan, then DirectX 12 (Windows) or OpenGL (Linux) where it fails. Next start.": "Vulkan, tiam DirectX 12 (Windows) aŭ OpenGL (Linux) kie ĝi malsukcesas. Sekva komenco.",
|
||||
"Water and glass in one buffer: fewer draw calls, a bit more VRAM. Next start.": "Akvo kaj glaso en unu bufro: malpli da tirvokoj, iom pli da VRAM. Sekva komenco.",
|
||||
"Mesh data sent to the GPU per frame. Lower is smoother while loading.": "Maŝdatenoj senditaj al la GPU per kadro. Malsupra estas pli glata dum ŝarĝo.",
|
||||
"Frame rate and frame times over the game, with a graph.": "Framfrekvenco kaj framtempoj dum la ludo, kun grafikaĵo.",
|
||||
"horizon.multiplayer.finding_friend": "Trovi la mondon de via amiko...",
|
||||
"horizon.multiplayer.not_signed_in": "Ĉi tiu servilo estas en reta reĝimo. Ensalutu per via Microsoft konto en la Horizon lanĉilo por aliĝi al ĝi.",
|
||||
"horizon.multiplayer.invalid_address": "Nevalida servila adreso: %s",
|
||||
"horizon.multiplayer.connected_friend_direct": "Konektita rekte al via amiko...",
|
||||
"horizon.multiplayer.connected_friend_relay": "Konektita al via amiko per la relajso...",
|
||||
"General": "Generalo",
|
||||
"Advanced": "Altnivela",
|
||||
"Undo": "Malfari",
|
||||
"Search options": "Serĉaj opcioj",
|
||||
"Shortcut": "Ŝparvojo",
|
||||
"Distance": "Distanco",
|
||||
"Display": "Montru",
|
||||
"Interface": "Interfaco",
|
||||
"Sky and weather": "Ĉielo kaj vetero",
|
||||
"Lighting and entities": "Lumigo kaj entoj",
|
||||
"Textures": "Teksturoj",
|
||||
"Image": "Bildo",
|
||||
"Chunk loading": "Peceta ŝarĝo",
|
||||
"Power": "Potenco",
|
||||
"Frames": "Kadroj",
|
||||
"Output": "Eligo",
|
||||
"Brightness": "Brilo",
|
||||
"How far you see, the window and the HUD.": "Kiom malproksime vi vidas, la fenestron kaj la HUD.",
|
||||
"The sky and weather, lighting, textures and the image.": "La ĉielo kaj vetero, lumigado, teksturoj kaj la bildo.",
|
||||
"Chunk loading, culling and power use.": "Chunk-ŝarĝado, forigo kaj potenco-uzo.",
|
||||
"How frames reach the screen, and the performance overlay.": "Kiel kadroj atingas la ekranon, kaj la rendimentan superkovron.",
|
||||
"Brighter-than-white output on an HDR display.": "Pli hela ol blanka eligo sur HDR-ekrano.",
|
||||
"Results for \"%s\"": "Rezultoj por \"%s\"",
|
||||
"No settings match.": "Neniuj agordoj kongruas.",
|
||||
"horizon.title.not_affiliated": "Ne aligita kun Mojang aŭ Microsoft",
|
||||
"horizon.extras.header.lighting": "Lumigo",
|
||||
"horizon.extras.header.third_person": "Tria persono",
|
||||
"horizon.extras.header.particles": "Partikloj",
|
||||
"horizon.extras.header.inventory": "Inventaro",
|
||||
"horizon.extras.header.chat": "Babilado",
|
||||
"horizon.extras.header.multiplayer": "Plurludanto",
|
||||
"horizon.extras.header.sound": "Sono",
|
||||
"horizon.extras.header.menus": "Menuoj",
|
||||
"horizon.extras.fullbright": "Plenluma",
|
||||
"horizon.extras.dynamic_lights": "Dinamikaj lumoj",
|
||||
"horizon.extras.own_name_tag": "Propra nometikedo",
|
||||
"horizon.extras.hide_block_particles": "Kaŝi blok-rompajn partiklojn",
|
||||
"horizon.extras.auto_reconnect": "Aŭtomata rekonekto",
|
||||
"horizon.extras.ui_sound_reserve": "Konservu kanalojn por UI-sonoj",
|
||||
"horizon.extras.music_page": "Muzika paĝo",
|
||||
"horizon.extras.mouse_tweaks": "Mouse Tweaks kontroloj",
|
||||
"horizon.extras.mouse_tweaks_wheel": "Rulumrado movas erojn",
|
||||
"horizon.extras.sort": "Ordigi butonojn",
|
||||
"horizon.extras.sort_key": "Ordiga klavo",
|
||||
"horizon.extras.no_ai": "Neniu AI",
|
||||
"horizon.extras.agent_control": "Agentkontrolo",
|
||||
"horizon.extras.discord_presence": "Discord Riĉa Ĉeesto",
|
||||
"horizon.extras.splitscreen": "Splitekrano",
|
||||
"horizon.extras.chat_animation": "Glata babilado",
|
||||
"horizon.extras.chat_indicator": "Mesaĝa indikilo",
|
||||
"horizon.extras.wheel_cycles_settings": "Rulumrado ŝanĝas agordojn",
|
||||
"horizon.extras.pack_browser": "Retumilo pri paka rimedo",
|
||||
"horizon.extras.fullbright.tooltip": "Montru blokojn kaj entojn ĉe plena lumo, eĉ en malhelaj lokoj.",
|
||||
"horizon.extras.dynamic_lights.tooltip": "Torĉoj kaj aliaj lumfontoj tenis, faligis aŭ sur fajro lumigas la blokojn ĉirkaŭ ili.",
|
||||
"horizon.extras.own_name_tag.tooltip": "Montras vian nomon super via kapo en tria persono, kiel aliaj ludantoj vidas ĝin. Kaŝita kiam la servilo kaŝas la nomojn de via teamo aŭ vi estas nevidebla.",
|
||||
"horizon.extras.hide_block_particles.tooltip": "Kaŝas la derompaĵojn, kiuj krevas el rompita bloko kaj diseriĝas de tiu, kiun vi minas. Aliaj partikloj restas.",
|
||||
"horizon.extras.auto_reconnect.tooltip": "Reeniĝas al servilo post perdita konekto aŭ rekomenco, neniam post piedbato aŭ malpermeso.",
|
||||
"horizon.extras.ui_sound_reserve.tooltip": "Sonoj en la mondo lasas 16 el la 247 sonkanaloj liberaj, do inundo da ili (granda eksplodo) ne povas silentigi menuklakojn.",
|
||||
"horizon.extras.music_page.tooltip": "Muziko & Sonoj ricevas paĝon Muziko...: ludu iun ajn enkonstruitan trakon nun aŭ malŝaltu unu por ke la ludo ĉesu elekti ĝin. Nenio ŝanĝiĝas ĝis vi malŝaltas trakon.",
|
||||
"horizon.extras.mouse_tweaks.tooltip": "Dekstre-tiri lokas po unu por fendeto, maldekstre-treni kolektas la tenitan objekton, Shift + maldekstra-tiri movas ĉiun fendon.",
|
||||
"horizon.extras.mouse_tweaks_wheel.tooltip": "Suben sendas unu objekton de la fendo al la alia flanko, supren alportas unu reen.",
|
||||
"horizon.extras.sort.tooltip": "Ordigas la inventaron, kestojn, barelojn, ender-kestojn kaj ŝulker-skatolojn en krea klapeta ordo, kunfandante stakojn.",
|
||||
"horizon.extras.sort_key.tooltip": "Ordigas la parton sub la kursoro. Klaku, tiam premu klavon; Eskapo malligas ĝin.",
|
||||
"horizon.extras.no_ai.tooltip": "Kaŝas kaj malŝaltas ĉiun AI-funkcion: agentkontrolo, horizon-ctl kaj la MCP-serviloj. Ankaŭ la ŝaltilo de la lanĉilo.",
|
||||
"horizon.extras.agent_control.tooltip": "Via propra AI-agento povas ludi ĉi tiun ludon per horizon-ctl aŭ MCP-kliento, nur en ĉi tiu komputilo.",
|
||||
"horizon.extras.discord_presence.tooltip": "Montras Ludante Horizon sur via Discord profilo dum Discord funkcias: menuoj, unuludanto aŭ plurludanto, la dimensio kaj la tempo ludata. Neniam mondnomo aŭ adreso de servilo.",
|
||||
"Calibrate...": "Kalibri...",
|
||||
"Calibrate Anyway...": "Kalibru ĉiuokaze...",
|
||||
"Use Automatic Setup": "Uzu Aŭtomatan Agordon",
|
||||
"Shortcut: %s": "Ŝparvojo: %s",
|
||||
"Next": "Poste",
|
||||
"HDR Calibration %s/%s: %s": "HDR-Kalibrado %s/%s: %s",
|
||||
"Sets the three below full screen, one test picture at a time.": "Agordas la tri sub plenan ekranon, unu testan bildon samtempe.",
|
||||
"A key that opens this screen from the game. Not bound at first.": "Ŝlosilo, kiu malfermas ĉi tiun ekranon de la ludo. Komence ne ligita.",
|
||||
"Your display didn't say how bright it gets: calibrate to set it up.": "Via ekrano ne diris kiom brilas ĝi fariĝas: kalibru por agordi ĝin.",
|
||||
"Already set up for your display. Only calibrate if HDR looks wrong.": "Jam agordita por via ekrano. Nur kalibru se HDR aspektas malĝusta.",
|
||||
"Puts Peak Brightness and Paper White back to your display's setup.": "Remetas Pintan Brilon kaj Paperan Blankan al la agordo de via ekrano.",
|
||||
"Set up for your display. Leave on Auto unless it looks wrong.": "Agordu por via ekrano. Lasu Aŭtomate krom se ĝi aspektas malĝusta.",
|
||||
"Lower it until the logo just disappears into the black.": "Mallevu ĝin ĝis la emblemo simple malaperas en la nigran.",
|
||||
"Raise it until the logo just disappears into the bright square.": "Levu ĝin ĝis la emblemo simple malaperos en la helan kvadraton.",
|
||||
"Make the card a white that's comfortable to look at for a long time, in the light you play in.": "Faru la karton blankan, kiu estas komforta rigardi dum longa tempo, en la lumo en kiu vi ludas.",
|
||||
"horizon.splitscreen.profiles.forget": "Forgesu",
|
||||
"horizon.splitscreen.profiles.create": "Krei",
|
||||
"horizon.splitscreen.profiles.you": " - vi",
|
||||
"horizon.splitscreen.profiles.forget_named": "Forgesu %s",
|
||||
"horizon.splitscreen.profiles.previous": "Antaŭa",
|
||||
"horizon.splitscreen.profiles.next": "Poste",
|
||||
"horizon.splitscreen.profiles.new_button": "Nova Profilo...",
|
||||
"horizon.splitscreen.profiles.forget_title": "Forgesu profilon?",
|
||||
"horizon.splitscreen.profiles.forget_leaves": "Ĝi forlasas la liston de ĉi tiu kazo.",
|
||||
"horizon.splitscreen.profiles.forget_kept": "Monda progreso kaj agordoj estas konservitaj.",
|
||||
"horizon.splitscreen.profiles.new_title": "Nova Profilo",
|
||||
"horizon.splitscreen.profiles.name_hint": "Nomo (3 ĝis 16 literoj, ciferoj, _)",
|
||||
"horizon.splitscreen.profiles.switch_title": "Ŝanĝu profilon",
|
||||
"horizon.splitscreen.profiles.offline_note": "Senretaj profiloj apartenas al ĉi tiu kazo",
|
||||
"horizon.splitscreen.profiles.move": "Movu kien vi ludas",
|
||||
"horizon.splitscreen.profiles.move_place": "Movu kien vi ludas: %s",
|
||||
"horizon.friends.title": "Ludu kun Amikoj",
|
||||
"horizon.friends.hint": "Amikoj algluas la kodon post la butono Amikoj de la titolekrano, en Rekta Konekto aŭ sur la Luda paĝo de la lanĉilo.",
|
||||
"horizon.friends.copied": "Kopiita",
|
||||
"horizon.friends.copy_code": "Kopiu Kodon",
|
||||
"horizon.friends.stop_sharing": "Ĉesu Kundividon",
|
||||
"horizon.friends.none_yet": "Ankoraŭ neniuj amikoj ĉi tie.",
|
||||
"horizon.friends.here_now": "Ĉi tie nun: %s",
|
||||
"horizon.friends.share_intro": "Kunhavigu ĉi tiun mondon malantaŭ invitkodo: ĝi malfermiĝas al LAN, kaj amikoj en la interreto aliĝas kun la kodo. Neniu servilo nia estas implikita.",
|
||||
"horizon.friends.start_sharing": "Komencu Kunhavigi",
|
||||
"horizon.friends.troubleshooting": "Solvado de problemoj...",
|
||||
"horizon.friends.stopped": "Ĉesis kunhavigi la invitkodon.",
|
||||
"horizon.friends.short_code_changed": "Iu daŭre provis malĝustan mallongan kodon, do ĝi ŝanĝiĝis.",
|
||||
"horizon.friends.wrong_code": "Iu provis malĝustan kodon.",
|
||||
"horizon.friends.code_ready": "Via invitkodo estas preta: Luda Menuo, Ludu kun Amikoj. Kopiu ĝin kaj sendu ĝin al viaj amikoj.",
|
||||
"horizon.friends.share_failed": "Ne povis dividi la mondon: %s",
|
||||
"horizon.friends.finding_route": "Trovi kiel amikoj povas atingi vin...",
|
||||
"horizon.osk.space": "Spaco",
|
||||
"horizon.osk.delete": "Forigi",
|
||||
"horizon.osk.type": "Tajpu",
|
||||
"horizon.osk.symbols": "Simboloj",
|
||||
"horizon.osk.close": "Fermu",
|
||||
"horizon.extras.chat_animation.tooltip": "Nova babillinio glitas enen de maldekstre dum ĝi fadas, anstataŭ aperi tute.",
|
||||
"horizon.extras.chat_indicator.tooltip": "La kolora stango maldekstre de babillinio.",
|
||||
"horizon.extras.wheel_cycles_settings.tooltip": "La rula rado super butono en la agordoj ŝanĝas sian valoron, kiel en vanilo. Malŝaltita, la rado nur rulumas la liston.",
|
||||
"horizon.extras.pack_browser.tooltip": "Elektu Rimedo-Pakojn ricevas butonon Aldoni, kiu serĉas Modrinth kaj instalas pakon en viajn pakajn dosierujojn. Malŝaltita, la ludo neniam kontaktas Modrinth.",
|
||||
"horizon.extras.splitscreen.tooltip": "En mondo, alia regilo povas aliĝi kiel nova ludanto: premu A kiam ĝi petas, tiam elektu profilon kaj kie ludi.",
|
||||
"horizon.splitscreen.setup.monitor": "Monitoro %s",
|
||||
"horizon.splitscreen.setup.monitor_unknown": "monitoro",
|
||||
"horizon.splitscreen.setup.window": "Fenestro %s",
|
||||
"horizon.splitscreen.setup.new_window": "Nova fenestro",
|
||||
"horizon.splitscreen.setup.fill_monitor": "Plenigu %s",
|
||||
"horizon.splitscreen.setup.done": "Farita",
|
||||
"horizon.splitscreen.setup.off": "Malŝaltita",
|
||||
"horizon.splitscreen.setup.player": "Ludanto %s",
|
||||
"horizon.splitscreen.setup.revert": "Reiri",
|
||||
"horizon.splitscreen.setup.apply": "Apliki",
|
||||
"horizon.splitscreen.setup.warning.empty_main": "Neniu ludas en Fenestro 1: ĝi kaŝas",
|
||||
"horizon.splitscreen.setup.warning.empty_close": "Neniu ludas en Fenestro %s: ĝi fermiĝas sur Apliki",
|
||||
"horizon.splitscreen.setup.warning.empty_new": "Neniu ludas en Fenestro %s: ĝi ne malfermos",
|
||||
"horizon.splitscreen.setup.warning.on_main": "Fenestro %s plenigas la ekranon de Fenestro 1: ĝiaj ludantoj ludas en Fenestro 1",
|
||||
"horizon.splitscreen.setup.warning.unplugged": "La ekrano de Fenestro %s ne estas konektita: ĝiaj ludantoj ludas en Fenestro 1",
|
||||
"horizon.splitscreen.setup.status.off": "Splitekrano estas malŝaltita.",
|
||||
"horizon.splitscreen.setup.status.enable_hint": "Ŝaltu ĝin, tiam premu butonon de alia regilo en mondo.",
|
||||
"horizon.splitscreen.setup.status.join_hint": "Premu A por aliĝi kaj elekti profilon.",
|
||||
"horizon.splitscreen.setup.status.idle": "Splitekrano neaktiva",
|
||||
"horizon.splitscreen.setup.status.alone": "Neniuj aliaj lokaj ludantoj.",
|
||||
"horizon.splitscreen.setup.status.solo_controls": "Solaj kontroloj kaj regilo-religoj estas senŝanĝaj.",
|
||||
"horizon.splitscreen.setup.window_empty": "Fenestro %s: malplena",
|
||||
"horizon.splitscreen.setup.note.select": "Alklaku ludanton aŭ trenu ĝin al fenestro aŭ ekrano.",
|
||||
"horizon.splitscreen.setup.note.apply": "Apliki por ludi tiamaniere, Reiru por malfari.",
|
||||
"horizon.splitscreen.setup.note.place": "Kie devus ludi %s?",
|
||||
"horizon.splitscreen.setup.this_player": "ĉi tiu ludanto",
|
||||
"horizon.splitscreen.setup.switch_disabled": "Splitekrano malŝaltas post kiam la aliaj foriris (ilia paŭza menuo).",
|
||||
"horizon.splitscreen.setup.window_place": "Fenestro %s (%s de %s)",
|
||||
"horizon.splitscreen.setup.names": "Nomoj",
|
||||
"horizon.splitscreen.setup.identify": "Identigi",
|
||||
"horizon.splitscreen.setup.layout.two": "2 kundivido: %s",
|
||||
"horizon.splitscreen.setup.layout.three": "3 kundivido: %s",
|
||||
"horizon.splitscreen.setup.layout.two.0": "Aŭtomate",
|
||||
"horizon.splitscreen.setup.layout.two.1": "Flank-al-flanke",
|
||||
"horizon.splitscreen.setup.layout.two.2": "Supre kaj malsupre",
|
||||
"horizon.splitscreen.setup.layout.three.0": "Unu larĝa supre",
|
||||
"horizon.splitscreen.setup.layout.three.1": "Unu alta maldekstre",
|
||||
"horizon.splitscreen.setup.layout.three.2": "Flank-al-flanke",
|
||||
"horizon.splitscreen.setup.help.player": "Klaku aŭ trenu %s por movi ilin.",
|
||||
"horizon.splitscreen.setup.help.layout_auto": "%s (flank-al-flanke kiam la fenestro estas larĝa). Premu por ŝanĝi.",
|
||||
"horizon.splitscreen.setup.help.layout": "%s. Premu por ŝanĝi.",
|
||||
"horizon.splitscreen.setup.help.switch": "Splitekrano por ĉi tiu komputilo, ŝaltita aŭ malŝaltita.",
|
||||
"horizon.splitscreen.setup.help.identify": "La vido de ĉiu ludanto montras en kiu fenestro ĝi estas.",
|
||||
"horizon.splitscreen.setup.help.names": "La nomo de ĉiu ludanto en la angulo de sia vido.",
|
||||
"horizon.splitscreen.setup.help.revert": "Malfaru la ŝanĝojn ankoraŭ ne aplikitajn.",
|
||||
"horizon.splitscreen.setup.help.apply": "Ludu kiel la mapo montras.",
|
||||
"horizon.splitscreen.setup.help.unchanged": "Ankoraŭ nenio ŝanĝiĝis.",
|
||||
"horizon.splitscreen.setup.give_up_pad": "Rezignu Pad",
|
||||
"horizon.splitscreen.prompt.controller_connected": "Regilo konektita",
|
||||
"horizon.splitscreen.prompt.controller_disconnected": "Regilo malkonektita",
|
||||
"horizon.splitscreen.prompt.controller_disconnected.hint": "Rekonektu ĝin, aŭ premu butonon sur alia",
|
||||
"horizon.splitscreen.prompt.join.one": "%s volas aliĝi",
|
||||
"horizon.splitscreen.prompt.join.many": "%s regiloj volas aliĝi",
|
||||
"horizon.splitscreen.prompt.join.yes": "Aliĝu",
|
||||
"horizon.splitscreen.prompt.join.as_p1": "Ludu kiel P1",
|
||||
"horizon.splitscreen.prompt.join.no": "Ne",
|
||||
"horizon.splitscreen.prompt.lost": "%s: regilo malkonektita",
|
||||
"horizon.splitscreen.prompt.lost.use_another": "Uzu alian",
|
||||
"horizon.splitscreen.prompt.lost.leave": "Foriru",
|
||||
"horizon.splitscreen.setup.help.give_up_pad": "Via regilo ĉesas veturigi vin kaj estas proponita aliĝi (A).",
|
||||
"horizon.splitscreen.setup.note.held_at": "%s al %s: A faligas ĝin ĉi tien, B remetas ĝin.",
|
||||
"horizon.splitscreen.setup.note.held": "%s kaptis: maldekstre/dekstre elektas kie, A faligas, B remetas ĝin.",
|
||||
"Hides models behind opaque blocks. Async checks off-thread; entities tick.": "Kaŝas modelojn malantaŭ maldiafanaj blokoj. Async kontrolas eksterfadenon; entoj tiktas.",
|
||||
"Block Entities": "Blokaj Entoj",
|
||||
"Shulker Boxes": "Ŝulkeraj Kestoj",
|
||||
"Reuses settled boxes; lid movement stays animated.": "Reuzas fiksitajn skatolojn; klapomovo restas vigla.",
|
||||
"Signs": "Signoj",
|
||||
"Reuses sign text until text, light, or font changes.": "Reuzas signan tekston ĝis teksto, lumo aŭ tiparo ŝanĝiĝas.",
|
||||
"Decorated Pots": "Ornitaj Potoj",
|
||||
"Reuses still pots; break wobble and sherd changes redraw.": "Reuzas ankoraŭ potojn; rompi ŝanceliĝon kaj ŝancelŝanĝojn redesegni.",
|
||||
"Bells": "Sonoriloj",
|
||||
"Reuses still bells; ringing stays animated.": "Reuzas ankoraŭ sonorilojn; sonorado restas vigla.",
|
||||
"Chests": "Kestoj",
|
||||
"Reuses closed chests; moving lids stay animated.": "Reuzas fermitajn kestojn; movantaj kovriloj restas viglaj.",
|
||||
"Banners": "Standardoj",
|
||||
"Reuses poles; flags and pattern layers still update.": "Reuzas polojn; flagoj kaj ŝablono tavoloj ankoraŭ ĝisdatigas.",
|
||||
"Copper Golem Statues": "Kupro-Golemaj Statuoj",
|
||||
"Reuses statue geometry until its block state changes.": "Reuzas statuan geometrion ĝis ĝia bloka stato ŝanĝiĝas.",
|
||||
"Leaf Culling": "Foliĉado",
|
||||
"Every leaf face. Vanilla's fancy leaves.": "Ĉiu folia vizaĝo. La fantaziaj folioj de vanilo.",
|
||||
"Distant Plant Dither": "Malproksima Plant Dither",
|
||||
"Keeps fine plants in high-res packs from fading far away.": "Malproksimigas bonajn plantojn en alt-rezultaj pakoj.",
|
||||
"Screenshot Quality": "Ekrankopio Kvalito",
|
||||
"F2 screenshots at this many times the game's resolution. Higher takes longer.": "F2-ekrankopioj je tio multfoje la rezolucio de la ludo. Pli alta daŭras pli longe.",
|
||||
"Frame Generation": "Frama Generacio",
|
||||
"Shows a made-up frame between each two real ones: smoother, a little more lag.": "Montras elfaritan kadron inter ĉiu du realaj: pli glata, iom pli da malfruo.",
|
||||
"Shadow Cache": "Ombra Deponejo",
|
||||
"Reuses the pack shadow map when sun, view and world match. Off by default.": "Reuzas la pak-ombromapon kiam suno, vido kaj mondo kongruas. Malŝaltita defaŭlte.",
|
||||
"Find BlueMap": "Trovu BlueMap",
|
||||
"On servers, finds their BlueMap web map for far terrain. Next join.": "Sur serviloj, trovas ilian BlueMap-retmapon por malproksima tereno. Poste aliĝu.",
|
||||
"BlueMap Radius": "BlueMap Radiuso",
|
||||
"How far around you BlueMap tiles are downloaded. Next join.": "Kiom malproksime ĉirkaŭ vi BlueMap-kaheloj estas elŝutitaj. Poste aliĝu.",
|
||||
"Synchronous": "Sinkrona",
|
||||
"Asynchronous": "Nesinkrona",
|
||||
"Solid": "Solida",
|
||||
"Solid Aggressive": "Solida Agresema",
|
||||
"Hollow": "Kava",
|
||||
"Leaves fully inside a canopy draw solid: fewer see-through layers.": "Folioj plene ene de baldakeno tiras solidan: malpli da travideblaj tavoloj.",
|
||||
"Leaves with one open side draw solid too: faster, chunkier edges.": "Folioj kun unu malfermita flanko ankaŭ desegnas solidan: pli rapidaj, pli dikaj randoj.",
|
||||
"Drops faces between leaves: faster, but gaps look through.": "Faligas vizaĝojn inter folioj: pli rapide, sed interspacoj trarigardas.",
|
||||
"Hotbar: Previous Slot": "Hotbar: Antaŭa Slot",
|
||||
"Hotbar: Next Slot": "Hotbar: Sekva Slot",
|
||||
"horizon.agent.connected.one": "Konektita: 1 agenta konekto",
|
||||
"horizon.agent.connected.many": "Konektitaj: %s agentaj konektoj",
|
||||
"horizon.agent.connected.one_ago": "Konektita: 1 agenta konekto, lasta komando antaŭ %s s",
|
||||
"horizon.agent.connected.many_ago": "Konektita: %s agentaj konektoj, lasta komando antaŭ %s s",
|
||||
"horizon.agent.waiting": "Atendante agenton.",
|
||||
"horizon.agent.off": "Malŝaltita: agentoj ne povas atingi ĉi tiun ludon.",
|
||||
"horizon.agent.session_opened": "Malfermita por ĉi tiu sesio de la programo kiu komencis la ludon.",
|
||||
"horizon.agent.socket": "Ingo: %s (kopiu la detalojn por ĝia plena vojo)",
|
||||
"horizon.agent.local_only": "Loka nur: agentoj sur ĉi tiu komputilo, neniam la reto.",
|
||||
"Auto (%s nits)": "Aŭtomata (%s nits)",
|
||||
"Hides models behind opaque blocks. Entities update. Off with custom packs.": "Kaŝas modelojn malantaŭ maldiafanaj blokoj. Entoj ĝisdatigas. For per kutimaj pakoj.",
|
||||
"horizon.extras.repro_keys": "Registrado de ŝparvojoj",
|
||||
"horizon.extras.repro_keys.tooltip": "F3+R komencas aŭ ĉesigas reproduktan registradon kaj F3+E skribas ĝian pakaĵon. Malŝaltita defaŭlte: registrado kopias la mondon.",
|
||||
"horizon.agent.record_session": "Komencu Registradan Sesion",
|
||||
"horizon.agent.record_stop": "Ĉesu Registrado-Sesion",
|
||||
"horizon.agent.export_repro": "Eksportu Repro Bundle",
|
||||
"horizon.repro.started": "Registrado komenciĝis; F3+R haltigas ĝin kaj skribas la pakaĵon.",
|
||||
"horizon.repro.stopped": "Registrado ĉesis: %s",
|
||||
"horizon.repro.bundle": "Reprodukta pakaĵo: %s",
|
||||
"horizon.repro.no_recording": "Ankoraŭ ne estas registrado por eksporti.",
|
||||
"horizon.repro.replay_started": "Ripeto komenciĝis: %s",
|
||||
"horizon.pack.addInfo": "Aldonu rimedan pakon de Modrinth",
|
||||
"horizon.pack.addWorking": "Demandante Modrinth...",
|
||||
"horizon.pack.addNone": "Neniuj rimedpakaĵoj trovitaj",
|
||||
"horizon.pack.addTitle": "Aldonu Rimedan Pakon",
|
||||
"horizon.pack.install": "Instali",
|
||||
"horizon.pack.installing": "Instalado",
|
||||
"horizon.pack.installed": "Instalita",
|
||||
"horizon.pack.search": "Serĉu",
|
||||
"horizon.pack.searchHint": "Serĉu Modrinth...",
|
||||
"horizon.pack.filters": "Filtriloj",
|
||||
"horizon.pack.filter.realistic": "Realisma",
|
||||
"horizon.pack.filter.simplistic": "Simplisma",
|
||||
"horizon.pack.filter.vanillaLike": "Vanilsimila",
|
||||
"horizon.pack.addFailed": "La pako ne povis esti aldonita: %s",
|
||||
"horizon.extras.header.cosmetics": "Kosmetikaĵoj",
|
||||
"horizon.extras.cosmetics_mine": "Miaj kosmetikaĵoj",
|
||||
"horizon.extras.cosmetics_mine.tooltip": "Kaŝita: ĉiu Horizon-ludanto vidas vin sen viaj kosmetikaĵoj, vi inkluzivis. La sama ŝaltilo kiel la Vestoŝranko de la lanĉilo.",
|
||||
"horizon.extras.cosmetics_others": "Kosmetikaĵoj de aliaj ludantoj",
|
||||
"horizon.extras.cosmetics_others.tooltip": "Kion aliaj Horizon ludantoj portas: ĉion, nur siajn nometikedstilojn, aŭ nenion. Kaŝita, la ludo neniam demandas kion ili portas.",
|
||||
"horizon.extras.cosmetics_auras": "Aŭroj kaj spuroj de aliaj",
|
||||
"horizon.extras.cosmetics_auras.tooltip": "Aŭroj kaj spuroj kiujn aliaj ludantoj portas. Malŝaltita defaŭlte.",
|
||||
"horizon.extras.cosmetics.shown": "Montrita",
|
||||
"horizon.extras.cosmetics.hidden": "Kaŝita",
|
||||
"horizon.extras.cosmetics.name_tags": "Nomaj etikedoj nur"
|
||||
}
|
||||
@@ -10,7 +10,6 @@
|
||||
"horizon.options.move_deadzone": "Zona muerta de movimiento",
|
||||
"horizon.options.look_deadzone": "Zona muerta de vista",
|
||||
"horizon.options.button_glyphs": "Símbolos de botones",
|
||||
"horizon.options.menu_navigation": "Navegación de menús",
|
||||
"horizon.options.on_screen_keyboard": "Teclado en pantalla",
|
||||
"horizon.options.chat_delay": "Retardo del chat",
|
||||
"horizon.options.lightbar.health": "Salud",
|
||||
@@ -19,8 +18,6 @@
|
||||
"horizon.options.glyphs.xbox": "Xbox",
|
||||
"horizon.options.glyphs.playstation": "PlayStation",
|
||||
"horizon.options.glyphs.nintendo": "Nintendo",
|
||||
"horizon.options.menu_focus": "Foco",
|
||||
"horizon.options.menu_pointer": "Puntero",
|
||||
"horizon.options.keyboard.auto": "Automático",
|
||||
"horizon.options.keyboard.horizon": "Horizon",
|
||||
"horizon.options.keyboard.steam": "Steam",
|
||||
|
||||
@@ -0,0 +1,472 @@
|
||||
{
|
||||
"horizon.options.controller": "Kontroller",
|
||||
"horizon.options.vibration": "Vibratsioon",
|
||||
"horizon.options.adaptive_triggers": "Adaptiivsed päästikud",
|
||||
"horizon.options.lightbar": "Valgusriba",
|
||||
"horizon.options.look_sensitivity": "Vaate tundlikkus",
|
||||
"horizon.options.invert_x": "Vaate X-telje pööramine",
|
||||
"horizon.options.invert_y": "Vaate Y-telje pööramine",
|
||||
"horizon.options.sneak_button": "Hiilimisnupp",
|
||||
"horizon.options.move_deadzone": "Liikumise surnud tsoon",
|
||||
"horizon.options.look_deadzone": "Vaate surnud tsoon",
|
||||
"horizon.options.button_glyphs": "Nuppude glüüfid",
|
||||
"horizon.options.on_screen_keyboard": "Ekraaniklaviatuur",
|
||||
"horizon.options.chat_delay": "Vestluse viivitus",
|
||||
"horizon.options.lightbar.health": "Tervis",
|
||||
"horizon.options.lightbar.dimension": "Mõõtmed",
|
||||
"horizon.options.glyphs.auto": "Automaatne",
|
||||
"horizon.options.keyboard.auto": "Automaatne",
|
||||
"horizon.options.unavailable": "See funktsioon pole Horizonis veel saadaval.",
|
||||
"horizon.options.search": "Otsinguseaded...",
|
||||
"horizon.pages.mods": "Modifikatsioonid",
|
||||
"horizon.pages.shader_options": "Varjundi valikud",
|
||||
"horizon.pages.controller": "Kontrolleri sätted",
|
||||
"horizon.pages.controller_binds": "Kontroller seob",
|
||||
"horizon.pages.extras": "Horizoni lisad",
|
||||
"horizon.pages.settings": "Horizoni sätted",
|
||||
"horizon.pages.agent": "AI agent",
|
||||
"horizon.split.leave": "Lahku",
|
||||
"horizon.pages.split_settings": "Jagatud ekraani seaded",
|
||||
"horizon.pages.split_profiles": "Kes mängib?",
|
||||
"horizon.pages.split_setup": "Jagatud ekraani seadistamine",
|
||||
"horizon.pages.music": "Muusika",
|
||||
"horizon.pages.music.menu": "Menüü",
|
||||
"horizon.pages.music.overworld": "Ülemaailm",
|
||||
"horizon.pages.music.creative": "Loominguline",
|
||||
"horizon.pages.music.underwater": "Vee all",
|
||||
"horizon.pages.music.end": "Lõpp",
|
||||
"horizon.pages.music.credits": "Krediidid",
|
||||
"horizon.pages.music.overworld_biomes": "Ülemaailma elustikud",
|
||||
"horizon.pages.music.nether_biomes": "Nether bioom",
|
||||
"horizon.pages.music.end_biomes": "Lõpetage bioomid",
|
||||
"horizon.pages.music.other": "Muu muusika",
|
||||
"horizon.pages.music.empty": "Muusikalugusid pole: mängu helisid ei laadita.",
|
||||
"horizon.pages.music.tooltip": "Sisseehitatud lood vastavalt olukorrale: mängige kohe ühte või lülitage mis tahes välja, et mäng lõpetaks selle valimise.",
|
||||
"horizon.pages.settings.tooltip": "Horizoni enda seaded: graafika, kontrollerid, lisad ja modifikatsioonid.",
|
||||
"horizon.pages.graphics.tooltip": "Graafika lihtsalt: iga seade ütleb, kui palju see maksab.",
|
||||
"horizon.pages.graphics_advanced.tooltip": "Iga graafikaseade, Horizon kaasas, koos sellega, mis maksab.",
|
||||
"horizon.pages.controller.tooltip": "Kontrollerid: nende nupud, pulgad, vibratsioon ja menüüs navigeerimine.",
|
||||
"horizon.pages.extras.tooltip": "Valikulised täiendused, kõik vaikimisi välja lülitatud: mäng jääb vaniljeks, kuni selle sisse lülitate.",
|
||||
"horizon.pages.agent.tooltip": "Laske oma AI-agendil selles arvutis mängida: horizon-ctl ja MCP-kliendid.",
|
||||
"horizon.pages.split_profiles.tooltip": "Kes mängib: selles mängukaustas hoitav profiil.",
|
||||
"horizon.pages.split_setup.tooltip": "Aknad ja monitorid ning kes kus mängib.",
|
||||
"horizon.pages.shader_packs.tooltip": "Varjupaketid kaustast Shaderpacks: Horizoni oma ja need, mis on formaadis Shader/. Üks jookseb korraga.",
|
||||
"horizon.pages.mods.tooltip": "Horizoni jaoks tehtud modifikatsioonid horizon-mods kaustast. Igaüks neist töötab liivakastis ja jääb väljalülitatuks, kuni selle sisse lülitate.",
|
||||
"horizon.pages.open.graphics": "Graafika...",
|
||||
"horizon.pages.open.graphics_advanced": "Täiustatud graafika...",
|
||||
"horizon.pages.open.controller": "Kontrolleri seaded...",
|
||||
"horizon.pages.open.split_setup": "Jagatud ekraan...",
|
||||
"horizon.pages.open.extras": "Lisad...",
|
||||
"horizon.pages.open.mods": "Modifikatsioonid...",
|
||||
"horizon.pages.open.agent": "AI agent...",
|
||||
"horizon.pages.open.horizon_graphics": "Horizoni graafika...",
|
||||
"horizon.pages.open.controller_binds": "Kontroller seob...",
|
||||
"horizon.pages.open.horizon_settings": "Horizoni seaded...",
|
||||
"horizon.pages.open.music": "Muusika...",
|
||||
"horizon.mods.empty": "Modifikatsioone pole: asetage .hmod-failid kausta horizon-mods",
|
||||
"horizon.mods.stopped": " (Peatatud)",
|
||||
"horizon.mods.not_built": " (Ehitamata)",
|
||||
"horizon.mods.dev": " (arendaja)",
|
||||
"horizon.mods.settings": "Seaded",
|
||||
"horizon.mods.in_world": " (jätke maailm muutuma)",
|
||||
"horizon.mods.open_folder": "Avage kaust Mod",
|
||||
"horizon.shader_packs.empty": "Varjupakkideta: pange need varjupakkide kausta",
|
||||
"horizon.shader_options.open": "Varjundi valikud...",
|
||||
"horizon.shader_options.profile": "Profiil",
|
||||
"horizon.shader_options.loading": "Varjutuspaketi valikute lugemine...",
|
||||
"horizon.agent.copy_details": "Kopeerige ühenduse üksikasjad",
|
||||
"horizon.multiplayer.join": "Liitu",
|
||||
"horizon.multiplayer.cancel_reconnecting": "Tühista uuesti ühendamine",
|
||||
"horizon.multiplayer.join_friend": "Liituge sõbraga",
|
||||
"horizon.multiplayer.invite_code": "Kutsekood",
|
||||
"horizon.multiplayer.relay": "Relee (valikuline)",
|
||||
"Preset": "Eelseadistatud",
|
||||
"LOD Distance": "LOD vahemaa",
|
||||
"Far Detail": "Kauge detail",
|
||||
"Entity Culling": "Üksuste tapmine",
|
||||
"Chunk Updates": "Tükkide värskendused",
|
||||
"Upload Budget": "Laadi eelarve üles",
|
||||
"Sky": "Taevas",
|
||||
"Fog": "Udu",
|
||||
"Weather": "Ilm",
|
||||
"Animated Textures": "Animeeritud tekstuurid",
|
||||
"Present Mode": "Praegune režiim",
|
||||
"Worker Threads": "Tööliste niidid",
|
||||
"Resolution Scale": "Eraldusvõime skaala",
|
||||
"Anti-aliasing": "Antialiasing",
|
||||
"Upscaling": "Suurendamine",
|
||||
"Paper White": "Paber Valge",
|
||||
"Peak Brightness": "Maksimaalne heledus",
|
||||
"Black Level": "Must tase",
|
||||
"UI Brightness": "UI heledus",
|
||||
"Battery Mode": "Akurežiim",
|
||||
"Graphics API": "Graafika API",
|
||||
"Translucent Batching": "Läbipaistev pakkimine",
|
||||
"Performance Overlay": "Toimivuse ülekate",
|
||||
"Full Detail Distance": "Täielik detailne kaugus",
|
||||
"On": "Sees",
|
||||
"Off": "Väljas",
|
||||
"Unlimited": "Piiramatu",
|
||||
"Auto": "Automaatne",
|
||||
"Custom": "Kohandatud",
|
||||
"Performance": "Esitus",
|
||||
"Balanced": "Tasakaalustatud",
|
||||
"Quality": "Kvaliteet",
|
||||
"Ultra Performance": "Ultra jõudlus",
|
||||
"Native": "Natiivne",
|
||||
"Full": "Täis",
|
||||
"Reduced": "Vähendatud",
|
||||
"Efficient": "Tõhus",
|
||||
"Precise": "Täpne",
|
||||
"Auto (VSync)": "Automaatne (VSync)",
|
||||
"Mailbox": "Postkast",
|
||||
"Immediate": "Vahetu",
|
||||
"FPS and Graph": "FPS ja graafik",
|
||||
"No cost": "Ei mingeid kulusid",
|
||||
"Low cost": "Madalad kulud",
|
||||
"Medium cost": "Keskmine kulu",
|
||||
"High cost": "Kõrge hind",
|
||||
"Saves time": "Säästab aega",
|
||||
"Graphics": "Graafika",
|
||||
"Done": "Valmis",
|
||||
"This feature is not yet available in Horizon.": "See funktsioon pole Horizonis veel saadaval.",
|
||||
"Your display or system doesn't offer HDR output.": "Teie ekraan või süsteem ei paku HDR-väljundit.",
|
||||
"Turn HDR on to use it.": "Selle kasutamiseks lülitage HDR sisse.",
|
||||
"Your GPU or graphics API doesn't support it.": "Teie GPU või graafika API seda ei toeta.",
|
||||
"%s chunks": "%s tükki",
|
||||
"%s per frame": "%s kaadri kohta",
|
||||
"%s MiB/frame": "%s MiB/kaader",
|
||||
"%s KiB/frame": "%s KiB/kaader",
|
||||
"Auto (%s)": "Automaatne (%s)",
|
||||
"Full-detail terrain range. LOD Distance can extend local worlds farther.": "Täielik detailne maastikuvalik. LOD Distance võib laiendada kohalikke maailmu kaugemale.",
|
||||
"Coarse distant terrain in local worlds. Integrated GPUs stop at 128 chunks.": "Jäme kauge maastik kohalikes maailmades. Integreeritud GPU-de arv on 128 tükki.",
|
||||
"Reduced draws far terrain coarser: faster on this integrated GPU.": "Vähendatud joonistab maastikul jämedam: kiirem selle integreeritud GPU-ga.",
|
||||
"Reduced draws far terrain coarser, for GPUs it slows down.": "Vähendatud tõmbab maastikku jämedamalt, GPU-de puhul aeglustab.",
|
||||
"Field of view. Wider shows more terrain at once.": "Vaateväli. Laiem näitab korraga rohkem maastikku.",
|
||||
"Caps frames per second; a cap saves power and heat.": "Caps kaadrit sekundis; kork säästab elektrit ja soojust.",
|
||||
"Waits for the display's refresh: no tearing, a little latency.": "Ootab ekraani värskendust: ei rebene, väike latentsus.",
|
||||
"Size of menus and the HUD.": "Menüüde suurus ja HUD.",
|
||||
"Sets the options below together. Changing one makes it Custom.": "Määrab allolevad valikud koos. Ühe muutmine muudab selle kohandatud.",
|
||||
"Lava, fire and sunlight shine brighter than white. Needs an HDR display.": "Laava, tuli ja päikesevalgus säravad valgest heledamalt. Vajab HDR-ekraani.",
|
||||
"Your display's darkest black. 0 for OLED; LCDs glow a little.": "Teie ekraan on kõige tumedam must. 0 OLED-i jaoks; LCD-ekraanid helendavad veidi.",
|
||||
"How bright highlights get. Auto: the peak your system reports.": "Kui eredad esiletõstud saavad. Automaatne: tipp, millest süsteem teatab.",
|
||||
"How bright white paper and menus look. Auto: your desktop's white.": "Kuidas helevalge paber ja menüüd välja näevad. Automaatne: teie töölaud on valge.",
|
||||
"How bright the HUD and menus are, against paper white.": "Kui eredad on HUD ja menüüd pabervalge taustal.",
|
||||
"How far mobs, crops and machines keep working. CPU time.": "Kui kaugele mobid, põllukultuurid ja masinad töötavad. CPU aeg.",
|
||||
"How far away mobs and items are drawn, as a share of normal.": "Kui kaugele mobid ja esemed tõmmatakse, kui osa normaalsest.",
|
||||
"Skips terrain hidden behind closed sections. Off costs a lot.": "Jätab vahele suletud lõikude taha peidetud maastiku. Off maksab palju.",
|
||||
"Hides entities behind opaque blocks.": "Peidab olemid läbipaistmatute plokkide taha.",
|
||||
"No entity occlusion culling.": "Üksuse oklusiooni praakimine puudub.",
|
||||
"CPU occlusion test runs this frame.": "CPU oklusiooni test käivitab selle kaadri.",
|
||||
"Occlusion checks run on a worker thread.": "Oklusioonikontrollid käitatakse töötaja lõimel.",
|
||||
"Meshed sections uploaded per frame. Lower is smoother while loading.": "Ühe kaadri kohta on üles laaditud võrgulõigud. Alumine on laadimise ajal sujuvam.",
|
||||
"Soft shadows in corners. Costs chunk building time only.": "Nurkades pehmed varjud. Maksab ainult ehitusaja osa.",
|
||||
"Smaller copies of block textures for distant terrain: less shimmer.": "Plokkide tekstuuride väiksemad koopiad kauge maastiku jaoks: vähem sära.",
|
||||
"Blends grass and water colours across biomes when building chunks.": "Segab tükkide ehitamisel bioomide vahel muru ja veevärve.",
|
||||
"Cloud layer: off, flat (fast) or 3D (fancy).": "Pilvekiht: väljas, tasane (kiire) või 3D (väljamõeldud).",
|
||||
"How far clouds reach, in chunks.": "Kui kaugele pilved ulatuvad, tükkidena.",
|
||||
"Draws the sky, sun, moon and stars.": "Joonistab taevast, päikest, kuud ja tähti.",
|
||||
"Distance fog. Off shows the edge of the loaded world.": "Kaugus udu. Väljas näitab laaditud maailma serva.",
|
||||
"Draws rain and snow.": "Tõmbab vihma ja lund.",
|
||||
"How far rain and snow fall around you.": "Kui kaugele sajab vihma ja lund sinu ümber.",
|
||||
"How many particles effects spawn.": "Kui palju osakesi mõju kudema.",
|
||||
"Round shadows under mobs and items.": "Ümmargused varjud mobide ja esemete all.",
|
||||
"Leaves with see-through gaps. Off draws them solid.": "Lehed läbipaistvate vahedega. Off tõmbab need tugevaks.",
|
||||
"Sorts water and glass more exactly behind each other.": "Sorteerib vett ja klaasi täpsemalt üksteise taha.",
|
||||
"Which chunk rebuilds wait for the frame: none, nearby or yours.": "Millised ümberehitused ootavad kaadrit: puudub, läheduses või teie.",
|
||||
"Animates water, lava, fire and other moving textures.": "Animeerib vett, laavat, tuld ja muid liikuvaid tekstuure.",
|
||||
"World pixels per screen pixel. Below 100% is faster on the GPU.": "Maailma piksleid ekraani piksli kohta. Alla 100% on GPU puhul kiirem.",
|
||||
"Smooths jagged edges. FXAA: softer. TAA: smoothest, moving things may trail.": "Silustab sakilised servad. FXAA: pehmem. TAA: kõige sujuvamad, liikuvad asjad võivad järele jääda.",
|
||||
"Renders the world smaller and rebuilds it with TAA. Faster, softer.": "Muudab maailma väiksemaks ja ehitab selle TAA abil uuesti üles. Kiirem, pehmem.",
|
||||
"HDR output on an HDR display: lava, fire and sunlight shine brighter.": "HDR-väljund HDR-ekraanil: laava, tuli ja päikesevalgus säravad eredamalt.",
|
||||
"How frames reach the screen while VSync is off.": "Kuidas raamid ekraanile jõuavad, kui VSync on välja lülitatud.",
|
||||
"Efficient sleeps until the next frame; Precise spins, like vanilla.": "Tõhusad magamised kuni järgmise kaadrini; Täpsed keerutused, nagu vanilje.",
|
||||
"Fills the screen (borderless).": "Täidab ekraani (ääristeta).",
|
||||
"Brightens dark places.": "Teeb tumedad kohad heledamaks.",
|
||||
"Lowers the frame rate when minimised, or idle too.": "Vähendab kaadrisagedust, kui see on minimeeritud või ka tühikäigul.",
|
||||
"Sways the view while walking.": "Kõndib kõndides vaadet.",
|
||||
"Fades newly loaded chunks in.": "Peidab äsja laaditud tükid sisse.",
|
||||
"Darkens the screen's edges.": "Tumendab ekraani servi.",
|
||||
"Shows when the world saves.": "Näitab, millal maailm päästab.",
|
||||
"Shows attack cooldown.": "Näitab rünnaku jahtumist.",
|
||||
"60 FPS cap (30 in menus or unfocused), half the workers: less power.": "60 kaadrit sekundis (menüüdes või fokuseerimata 30 kaadrit sekundis), pooled töötajad: vähem võimsust.",
|
||||
"Threads that generate, light and mesh chunks. Next start.": "Niidid, mis tekitavad, valgustavad ja võrgustavad tükke. Järgmine algus.",
|
||||
"Vulkan, then DirectX 12 (Windows) or OpenGL (Linux) where it fails. Next start.": "Vulkan, seejärel DirectX 12 (Windows) või OpenGL (Linux), kui see ebaõnnestub. Järgmine algus.",
|
||||
"Water and glass in one buffer: fewer draw calls, a bit more VRAM. Next start.": "Vesi ja klaas ühes puhvris: vähem joonistuskõnesid, natuke rohkem VRAM-i. Järgmine algus.",
|
||||
"Mesh data sent to the GPU per frame. Lower is smoother while loading.": "GPU-le saadetud võrguandmed kaadri kohta. Alumine on laadimise ajal sujuvam.",
|
||||
"Frame rate and frame times over the game, with a graph.": "Kaadrisagedus ja kaadriajad mängu jooksul koos graafikuga.",
|
||||
"horizon.multiplayer.finding_friend": "Oma sõbra maailma leidmine...",
|
||||
"horizon.multiplayer.not_signed_in": "See server on võrgurežiimis. Sellega liitumiseks logige Horizoni käivitajas sisse oma Microsofti kontoga.",
|
||||
"horizon.multiplayer.invalid_address": "Vale serveri aadress: %s",
|
||||
"horizon.multiplayer.connected_friend_direct": "Ühendatakse otse teie sõbraga...",
|
||||
"horizon.multiplayer.connected_friend_relay": "Sõbraga relee kaudu ühendatud...",
|
||||
"General": "Kindral",
|
||||
"Advanced": "Täpsemalt",
|
||||
"Undo": "Võta tagasi",
|
||||
"Search options": "Otsinguvalikud",
|
||||
"Shortcut": "Otsetee",
|
||||
"Distance": "Kaugus",
|
||||
"Display": "Ekraan",
|
||||
"Interface": "Liides",
|
||||
"Sky and weather": "Taevas ja ilm",
|
||||
"Lighting and entities": "Valgustus ja üksused",
|
||||
"Textures": "Tekstuurid",
|
||||
"Image": "Pilt",
|
||||
"Chunk loading": "Tükkide laadimine",
|
||||
"Culling": "Tapmine",
|
||||
"Power": "Võimsus",
|
||||
"Frames": "Raamid",
|
||||
"Overlay": "Ülekate",
|
||||
"Output": "Väljund",
|
||||
"Brightness": "Heledus",
|
||||
"How far you see, the window and the HUD.": "Kui kaugele näete, aken ja HUD.",
|
||||
"The sky and weather, lighting, textures and the image.": "Taevas ja ilm, valgustus, tekstuurid ja pilt.",
|
||||
"Chunk loading, culling and power use.": "Tükkide laadimine, praakimine ja energiakasutus.",
|
||||
"How frames reach the screen, and the performance overlay.": "Kuidas kaadrid ekraanile jõuavad ja jõudluse ülekate.",
|
||||
"Brighter-than-white output on an HDR display.": "Valgest heledam väljund HDR-ekraanil.",
|
||||
"Results for \"%s\"": "Tulemused päringule \"%s\"",
|
||||
"No settings match.": "Ükski seade ei sobi.",
|
||||
"horizon.title.not_affiliated": "Ei ole seotud Mojangi ega Microsoftiga",
|
||||
"horizon.extras.header.lighting": "Valgustus",
|
||||
"horizon.extras.header.third_person": "Kolmas isik",
|
||||
"horizon.extras.header.particles": "Osakesed",
|
||||
"horizon.extras.header.inventory": "Inventuur",
|
||||
"horizon.extras.header.chat": "Vestlus",
|
||||
"horizon.extras.header.multiplayer": "Mitmikmäng",
|
||||
"horizon.extras.header.sound": "Heli",
|
||||
"horizon.extras.header.menus": "Menüüd",
|
||||
"horizon.extras.dynamic_lights": "Dünaamilised tuled",
|
||||
"horizon.extras.own_name_tag": "Oma nimesilt",
|
||||
"horizon.extras.hide_block_particles": "Peida ploki purunevad osakesed",
|
||||
"horizon.extras.auto_reconnect": "Automaatne taasühendamine",
|
||||
"horizon.extras.ui_sound_reserve": "Hoidke kasutajaliidese helide jaoks kanalid alles",
|
||||
"horizon.extras.music_page": "Muusika leht",
|
||||
"horizon.extras.mouse_tweaks": "Mouse Tweaksi juhtnupud",
|
||||
"horizon.extras.mouse_tweaks_wheel": "Kerimisratas liigutab üksusi",
|
||||
"horizon.extras.sort": "Sorteerimisnupud",
|
||||
"horizon.extras.sort_key": "Sorteerimisvõti",
|
||||
"horizon.extras.no_ai": "Ei mingit AI-d",
|
||||
"horizon.extras.agent_control": "Agendi kontroll",
|
||||
"horizon.extras.discord_presence": "Discordi rikkalik kohalolek",
|
||||
"horizon.extras.splitscreen": "Jagatud ekraan",
|
||||
"horizon.extras.chat_animation": "Sujuv vestlus",
|
||||
"horizon.extras.chat_indicator": "Sõnumi indikaator",
|
||||
"horizon.extras.wheel_cycles_settings": "Kerimisratas muudab seadeid",
|
||||
"horizon.extras.pack_browser": "Ressursipaketi brauser",
|
||||
"horizon.extras.fullbright.tooltip": "Kuva plokke ja üksusi täisvalguses, isegi pimedates kohtades.",
|
||||
"horizon.extras.dynamic_lights.tooltip": "Tõrvikud ja muud valgusallikad hoidsid, kukkusid või põlesid põlema, valgustavad neid ümbritsevaid klotse.",
|
||||
"horizon.extras.own_name_tag.tooltip": "Näitab teie nime teie pea kohal kolmandas isikus, nagu teised mängijad seda näevad. Peidetud, kui server peidab teie meeskonna nimed või olete nähtamatu.",
|
||||
"horizon.extras.hide_block_particles.tooltip": "Peidab prahiosakesed, mis purunenud plokist pursavad välja ja murenevad maha sellelt, mille kaevandasite. Teised osakesed jäävad.",
|
||||
"horizon.extras.auto_reconnect.tooltip": "Liitub serveriga uuesti pärast ühenduse katkemist või taaskäivitamist, mitte kunagi pärast lööki või keelamist.",
|
||||
"horizon.extras.ui_sound_reserve.tooltip": "Helid maailmas jätavad vabaks 16 helikanalit 247-st, nii et nende tulv (suur plahvatus) ei suuda menüüklõpse vaigistada.",
|
||||
"horizon.extras.music_page.tooltip": "Muusika ja helid saavad lehe Muusika...: mängige kohe mis tahes sisseehitatud lugu või lülitage see välja, et mäng lõpetaks selle valimise. Midagi ei muutu enne, kui lülitate raja välja.",
|
||||
"horizon.extras.mouse_tweaks.tooltip": "Parem-lohistamine asetab ühe pesa kohta, vasak-lohistamine kogub kinni hoitud üksuse, tõstuklahv + vasak-lohistamine liigutab iga pesa.",
|
||||
"horizon.extras.mouse_tweaks_wheel.tooltip": "Alla saadab ühe pesa elemendi teisele poole, üles toob ühe tagasi.",
|
||||
"horizon.extras.sort.tooltip": "Sorteerib laoseisud, kastid, tünnid, enderkastid ja shulkeri kastid loomingulises vahekaardi järjekorras, liites virnad.",
|
||||
"horizon.extras.sort_key.tooltip": "Sorteerib kursori all oleva osa. Klõpsake, seejärel vajutage klahvi; Põgenemine seob selle lahti.",
|
||||
"horizon.extras.no_ai.tooltip": "Peidab ja lülitab välja kõik AI funktsioonid: agendi juhtimine, horizon-ctl ja MCP-serverid. Ka kanderaketi lüliti.",
|
||||
"horizon.extras.agent_control.tooltip": "Teie enda tehisintellekti agent saab seda mängu mängida horizon-ctl-i või MCP-kliendi kaudu ainult selles arvutis.",
|
||||
"horizon.extras.discord_presence.tooltip": "Kuvab Discordi profiilil Play Horizon, kui Discord töötab: menüüd, üksik- või mitme mängijaga mäng, dimensioon ja mängimisaeg. Mitte kunagi maailma nime ega serveri aadressi.",
|
||||
"Calibrate...": "Kalibreeri...",
|
||||
"Calibrate Anyway...": "Kalibreerige ikkagi...",
|
||||
"Use Automatic Setup": "Kasutage automaatset seadistust",
|
||||
"Shortcut: %s": "Otsetee: %s",
|
||||
"Next": "Edasi",
|
||||
"HDR Calibration %s/%s: %s": "HDR-kalibreerimine %s/%s: %s",
|
||||
"Sets the three below full screen, one test picture at a time.": "Määrab kolm allolevat täisekraani, üks testpilt korraga.",
|
||||
"A key that opens this screen from the game. Not bound at first.": "Klahv, mis avab mängust selle ekraani. Alguses ei köideta.",
|
||||
"Your display didn't say how bright it gets: calibrate to set it up.": "Teie ekraan ei öelnud, kui hele see muutub: seadistamiseks kalibreerige.",
|
||||
"Already set up for your display. Only calibrate if HDR looks wrong.": "Teie kuva jaoks on juba seadistatud. Kalibreerige ainult siis, kui HDR tundub vale.",
|
||||
"Puts Peak Brightness and Paper White back to your display's setup.": "Tagab maksimaalse ereduse ja paberivalgeduse teie ekraani seadistustesse.",
|
||||
"Set up for your display. Leave on Auto unless it looks wrong.": "Seadistage oma kuva jaoks. Jätke valikule Auto, kui see ei tundu vale.",
|
||||
"Lower it until the logo just disappears into the black.": "Langetage seda, kuni logo kaob lihtsalt mustaks.",
|
||||
"Raise it until the logo just disappears into the bright square.": "Tõstke seda seni, kuni logo kaob heledasse ruutu.",
|
||||
"Make the card a white that's comfortable to look at for a long time, in the light you play in.": "Muuda kaart valgeks, mida on mugav pikka aega vaadata, selle valguses, milles mängid.",
|
||||
"horizon.splitscreen.profiles.forget": "Unusta",
|
||||
"horizon.splitscreen.profiles.create": "Loo",
|
||||
"horizon.splitscreen.profiles.you": " - sina",
|
||||
"horizon.splitscreen.profiles.forget_named": "Unusta %s",
|
||||
"horizon.splitscreen.profiles.previous": "Eelmine",
|
||||
"horizon.splitscreen.profiles.next": "Edasi",
|
||||
"horizon.splitscreen.profiles.new_button": "Uus profiil...",
|
||||
"horizon.splitscreen.profiles.forget_title": "Kas unustate profiili?",
|
||||
"horizon.splitscreen.profiles.forget_leaves": "See lahkub selle eksemplari loendist.",
|
||||
"horizon.splitscreen.profiles.forget_kept": "Maailma edenemist ja seadeid hoitakse alles.",
|
||||
"horizon.splitscreen.profiles.new_title": "Uus profiil",
|
||||
"horizon.splitscreen.profiles.name_hint": "Nimi (3 kuni 16 tähte, numbrit, _)",
|
||||
"horizon.splitscreen.profiles.switch_title": "Vaheta profiili",
|
||||
"horizon.splitscreen.profiles.offline_note": "Sellesse eksemplari kuuluvad võrguühenduseta profiilid",
|
||||
"horizon.splitscreen.profiles.move": "Liikuge sinna, kus mängite",
|
||||
"horizon.splitscreen.profiles.move_place": "Liikuge sinna, kus mängite: %s",
|
||||
"horizon.friends.title": "Mängige sõpradega",
|
||||
"horizon.friends.hint": "Sõbrad kleebivad koodi pealkirjaekraani nupu Sõbrad järele, otseühenduses või käivitusprogrammi Play lehel.",
|
||||
"horizon.friends.copied": "Kopeeritud",
|
||||
"horizon.friends.copy_code": "Kopeeri kood",
|
||||
"horizon.friends.stop_sharing": "Lõpeta jagamine",
|
||||
"horizon.friends.none_yet": "Siin pole veel sõpru.",
|
||||
"horizon.friends.here_now": "Siin praegu: %s",
|
||||
"horizon.friends.share_intro": "Jagage seda maailma kutsekoodi taga: see avaneb LAN-i ja Internetis olevad sõbrad liituvad koodiga. Ükski meie server ei ole sellega seotud.",
|
||||
"horizon.friends.start_sharing": "Alusta jagamist",
|
||||
"horizon.friends.troubleshooting": "Veaotsing...",
|
||||
"horizon.friends.stopped": "Kutsekoodi jagamine lõpetati.",
|
||||
"horizon.friends.short_code_changed": "Keegi proovis pidevalt valet lühikoodi, nii et see muutus.",
|
||||
"horizon.friends.wrong_code": "Keegi proovis vale koodi.",
|
||||
"horizon.friends.code_ready": "Teie kutsekood on valmis: Mängumenüü, Mängige sõpradega. Kopeerige see ja saatke see oma sõpradele.",
|
||||
"horizon.friends.share_failed": "Ei saanud maailma jagada: %s",
|
||||
"horizon.friends.finding_route": "Kuidas sõbrad teiega ühendust saavad…",
|
||||
"horizon.osk.space": "Kosmos",
|
||||
"horizon.osk.delete": "Kustuta",
|
||||
"horizon.osk.type": "Tüüp",
|
||||
"horizon.osk.symbols": "Sümbolid",
|
||||
"horizon.osk.close": "Sule",
|
||||
"horizon.extras.chat_animation.tooltip": "Uus vestlusliin libiseb vasakult sisse, kui see sumbub, selle asemel, et paista tervena.",
|
||||
"horizon.extras.chat_indicator.tooltip": "Vestlusrea vasakul olev värviline riba.",
|
||||
"horizon.extras.wheel_cycles_settings.tooltip": "Seadetes nupu kohal olev kerimisratas muudab selle väärtust, nagu vanilje puhul. Väljas, ratas kerib ainult loendit.",
|
||||
"horizon.extras.pack_browser.tooltip": "Ressursipaketi valikul kuvatakse nupp Lisa, mis otsib Modrinthi ja installib paketi teie pakettide kausta. Väljas, mäng ei võta kunagi Modrinthiga ühendust.",
|
||||
"horizon.extras.splitscreen.tooltip": "Maailmas saab uue mängijana liituda teine kontroller: vajutage A, kui see küsib, seejärel valige profiil ja kus mängida.",
|
||||
"horizon.splitscreen.setup.monitor_unknown": "monitor",
|
||||
"horizon.splitscreen.setup.window": "Aken %s",
|
||||
"horizon.splitscreen.setup.new_window": "Uus aken",
|
||||
"horizon.splitscreen.setup.fill_monitor": "Täida %s",
|
||||
"horizon.splitscreen.setup.done": "Valmis",
|
||||
"horizon.splitscreen.setup.on": "Sees",
|
||||
"horizon.splitscreen.setup.off": "Väljas",
|
||||
"horizon.splitscreen.setup.player": "Mängija %s",
|
||||
"horizon.splitscreen.setup.revert": "Taasta",
|
||||
"horizon.splitscreen.setup.apply": "Rakenda",
|
||||
"horizon.splitscreen.setup.warning.empty_main": "Keegi ei mängi aknas 1: see peidab",
|
||||
"horizon.splitscreen.setup.warning.empty_close": "Keegi ei mängi aknas %s: see suletakse rakenduses Rakenda",
|
||||
"horizon.splitscreen.setup.warning.empty_new": "Keegi ei mängi aknas %s: see ei avane",
|
||||
"horizon.splitscreen.setup.warning.on_main": "Aken %s täidab akna 1 monitori: selle mängijad mängivad aknas 1",
|
||||
"horizon.splitscreen.setup.warning.unplugged": "Akna %s monitor pole ühendatud: selle mängijad mängivad aknas 1",
|
||||
"horizon.splitscreen.setup.status.off": "Jagatud ekraan on välja lülitatud.",
|
||||
"horizon.splitscreen.setup.status.enable_hint": "Lülitage see sisse ja seejärel vajutage nuppu mõnel teisel kontrolleril maailmas.",
|
||||
"horizon.splitscreen.setup.status.join_hint": "Liitumiseks ja profiili valimiseks vajutage A.",
|
||||
"horizon.splitscreen.setup.status.idle": "Tükeldatud ekraan jõudeolekus",
|
||||
"horizon.splitscreen.setup.status.alone": "Teisi kohalikke mängijaid pole.",
|
||||
"horizon.splitscreen.setup.status.solo_controls": "Üksikjuhtimisseadmed ja kontrolleri tagasiside ei muutu.",
|
||||
"horizon.splitscreen.setup.window_empty": "Aken %s: tühi",
|
||||
"horizon.splitscreen.setup.note.select": "Klõpsake pleieril või lohistage see aknale või monitorile.",
|
||||
"horizon.splitscreen.setup.note.apply": "Sel viisil mängimiseks rakendage, tagasivõtmiseks ennista.",
|
||||
"horizon.splitscreen.setup.note.place": "Kus peaks %s mängima?",
|
||||
"horizon.splitscreen.setup.this_player": "see mängija",
|
||||
"horizon.splitscreen.setup.switch_disabled": "Jaotatud ekraan lülitub välja, kui teised on lahkunud (nende pausimenüü).",
|
||||
"horizon.splitscreen.setup.window_place": "Aken %s (%s/%s)",
|
||||
"horizon.splitscreen.setup.names": "Nimed",
|
||||
"horizon.splitscreen.setup.identify": "Tuvastage",
|
||||
"horizon.splitscreen.setup.layout.two": "2 jagamist: %s",
|
||||
"horizon.splitscreen.setup.layout.three": "3 jagamist: %s",
|
||||
"horizon.splitscreen.setup.layout.two.0": "Automaatne",
|
||||
"horizon.splitscreen.setup.layout.two.1": "Kõrvuti",
|
||||
"horizon.splitscreen.setup.layout.two.2": "Ülemine ja alumine",
|
||||
"horizon.splitscreen.setup.layout.three.0": "Pealt üks lai",
|
||||
"horizon.splitscreen.setup.layout.three.1": "Üks pikk vasakul",
|
||||
"horizon.splitscreen.setup.layout.three.2": "Kõrvuti",
|
||||
"horizon.splitscreen.setup.help.player": "Nende teisaldamiseks klõpsake või lohistage %s.",
|
||||
"horizon.splitscreen.setup.help.layout_auto": "%s (kõrvuti, kui aken on lai). Vajutage muutmiseks.",
|
||||
"horizon.splitscreen.setup.help.layout": "%s. Vajutage muutmiseks.",
|
||||
"horizon.splitscreen.setup.help.switch": "Selle arvuti jagatud ekraan, sisse või välja lülitatud.",
|
||||
"horizon.splitscreen.setup.help.identify": "Iga mängija vaade näitab, millises aknas ta on.",
|
||||
"horizon.splitscreen.setup.help.names": "Iga mängija nimi tema vaate nurgas.",
|
||||
"horizon.splitscreen.setup.help.revert": "Võta tagasi muudatused, mida pole veel rakendatud.",
|
||||
"horizon.splitscreen.setup.help.apply": "Mängige nii, nagu kaart näitab.",
|
||||
"horizon.splitscreen.setup.help.unchanged": "Midagi pole veel muutunud.",
|
||||
"horizon.splitscreen.setup.give_up_pad": "Loobu padjast",
|
||||
"horizon.splitscreen.prompt.controller_connected": "Kontroller ühendatud",
|
||||
"horizon.splitscreen.prompt.controller_disconnected": "Kontroller on lahti ühendatud",
|
||||
"horizon.splitscreen.prompt.controller_disconnected.hint": "Ühendage see uuesti või vajutage mõnel teisel nupul",
|
||||
"horizon.splitscreen.prompt.join.one": "%s soovib liituda",
|
||||
"horizon.splitscreen.prompt.join.many": "%s kontrollerit soovivad liituda",
|
||||
"horizon.splitscreen.prompt.join.yes": "Liitu",
|
||||
"horizon.splitscreen.prompt.join.as_p1": "Mängi kui P1",
|
||||
"horizon.splitscreen.prompt.join.no": "Ei",
|
||||
"horizon.splitscreen.prompt.lost": "%s: kontroller on lahti ühendatud",
|
||||
"horizon.splitscreen.prompt.lost.use_another": "Kasutage teist",
|
||||
"horizon.splitscreen.prompt.lost.leave": "Lahku",
|
||||
"horizon.splitscreen.setup.help.give_up_pad": "Teie kontroller lõpetab teie juhtimise ja talle pakutakse liitumist (A).",
|
||||
"horizon.splitscreen.setup.note.held_at": "%s kuni %s: A viskab selle siia, B paneb selle tagasi.",
|
||||
"horizon.splitscreen.setup.note.held": "%s korjatud: vasak/parem valib, kuhu, A kukub, B paneb tagasi.",
|
||||
"Hides models behind opaque blocks. Async checks off-thread; entities tick.": "Peidab mudelid läbipaistmatute plokkide taha. Async kontrollib lõimevälist; olemid tiksuvad.",
|
||||
"Block Entities": "Blokeeri üksused",
|
||||
"Shulker Boxes": "Shulkeri karbid",
|
||||
"Reuses settled boxes; lid movement stays animated.": "Taaskasutab settinud kaste; kaane liikumine jääb animeeritud.",
|
||||
"Signs": "Märgid",
|
||||
"Reuses sign text until text, light, or font changes.": "Kasutab märgiteksti uuesti, kuni tekst, valgustus või font muutub.",
|
||||
"Decorated Pots": "Kaunistatud potid",
|
||||
"Reuses still pots; break wobble and sherd changes redraw.": "Taaskasutab veel potte; murda võnkuma ja shed muutused uuesti joonistama.",
|
||||
"Bells": "Kellad",
|
||||
"Reuses still bells; ringing stays animated.": "Taaskasutab liikumatuid kellasid; helin jääb animeeritud.",
|
||||
"Chests": "Kummutid",
|
||||
"Reuses closed chests; moving lids stay animated.": "Taaskasutab suletud kaste; liikuvad kaaned jäävad animeeritud.",
|
||||
"Banners": "Bännerid",
|
||||
"Reuses poles; flags and pattern layers still update.": "Taaskasutab poste; lipud ja mustrikihid uuendatakse endiselt.",
|
||||
"Copper Golem Statues": "Vasest Golemi kujud",
|
||||
"Reuses statue geometry until its block state changes.": "Taaskasutab kuju geomeetriat, kuni selle ploki olek muutub.",
|
||||
"Leaf Culling": "Lehtede tapmine",
|
||||
"Every leaf face. Vanilla's fancy leaves.": "Iga lehe nägu. Vanilli uhked lehed.",
|
||||
"Keeps fine plants in high-res packs from fading far away.": "Hoiab kõrge eraldusvõimega pakendites peeneid taimi kaugele tuhmumise eest.",
|
||||
"Screenshot Quality": "Ekraanipildi kvaliteet",
|
||||
"F2 screenshots at this many times the game's resolution. Higher takes longer.": "F2 ekraanipildid selle mitmekordse mängu eraldusvõimega. Kõrgem võtab kauem aega.",
|
||||
"Frame Generation": "Raami genereerimine",
|
||||
"Shows a made-up frame between each two real ones: smoother, a little more lag.": "Näitab väljamõeldud kaadrit iga kahe päriskaadri vahel: sujuvam, veidi rohkem viivitust.",
|
||||
"Reuses the pack shadow map when sun, view and world match. Off by default.": "Taaskasutab paki varjukaarti, kui päike, vaade ja maailm ühtivad. Vaikimisi väljas.",
|
||||
"Find BlueMap": "Otsige üles BlueMap",
|
||||
"On servers, finds their BlueMap web map for far terrain. Next join.": "Serverites leiab nende BlueMapi veebikaardi kauge maastiku jaoks. Järgmine liitumine.",
|
||||
"BlueMap Radius": "BlueMap raadius",
|
||||
"How far around you BlueMap tiles are downloaded. Next join.": "Kui kaugele teie ümber BlueMapi paanid alla laaditakse. Järgmine liitumine.",
|
||||
"Synchronous": "Sünkroonne",
|
||||
"Asynchronous": "Asünkroonne",
|
||||
"Solid": "Tahke",
|
||||
"Solid Aggressive": "Tugev agressiivne",
|
||||
"Hollow": "Õõnes",
|
||||
"Leaves fully inside a canopy draw solid: fewer see-through layers.": "Lehed täielikult võra sees tõmbuvad tugevalt: vähem läbipaistvaid kihte.",
|
||||
"Leaves with one open side draw solid too: faster, chunkier edges.": "Ühe avatud küljega lehed on samuti tugevad: kiiremad ja turskemad servad.",
|
||||
"Drops faces between leaves: faster, but gaps look through.": "Langeb näod lehtede vahele: kiiremini, kuid vahed paistavad läbi.",
|
||||
"Hotbar: Previous Slot": "Hotbar: eelmine pesa",
|
||||
"Hotbar: Next Slot": "Hotbar: järgmine pesa",
|
||||
"horizon.agent.connected.one": "Ühendatud: 1 agendiühendus",
|
||||
"horizon.agent.connected.many": "Ühendatud: %s agendi ühendused",
|
||||
"horizon.agent.connected.one_ago": "Ühendatud: 1 agendiühendus, viimane käsk %s s tagasi",
|
||||
"horizon.agent.connected.many_ago": "Ühendatud: %s agendiühendused, viimane käsk %s s tagasi",
|
||||
"horizon.agent.waiting": "Ootan agenti.",
|
||||
"horizon.agent.off": "Väljas: agendid ei pääse selle mängu juurde.",
|
||||
"horizon.agent.session_opened": "Selle seansi jaoks avas mängu käivitanud programm.",
|
||||
"horizon.agent.socket": "Pistikupesa: %s (kopeerige selle täieliku tee üksikasjad)",
|
||||
"horizon.agent.local_only": "Ainult kohalik: selles arvutis olevad agendid, mitte kunagi võrk.",
|
||||
"Auto (%s nits)": "Automaatne (%s nits)",
|
||||
"Hides models behind opaque blocks. Entities update. Off with custom packs.": "Peidab mudelid läbipaistmatute plokkide taha. Olemite värskendamine. Väljas kohandatud pakkidega.",
|
||||
"horizon.extras.repro_keys": "Salvestamise otseteed",
|
||||
"horizon.extras.repro_keys.tooltip": "F3+R alustab või peatab reprosalvestuse ja F3+E kirjutab selle paketi. Vaikimisi väljas: salvestis kopeerib maailma.",
|
||||
"horizon.agent.record_session": "Alustage salvestamise seanssi",
|
||||
"horizon.agent.record_stop": "Seansi salvestamise lõpetamine",
|
||||
"horizon.agent.export_repro": "Ekspordi Repro komplekt",
|
||||
"horizon.repro.started": "Salvestamine algas; F3+R peatab selle ja kirjutab kimbu.",
|
||||
"horizon.repro.stopped": "Salvestamine peatatud: %s",
|
||||
"horizon.repro.bundle": "Repro pakett: %s",
|
||||
"horizon.repro.no_recording": "Eksportimiseks pole veel salvestist.",
|
||||
"horizon.repro.replay_started": "Taasesitus algas: %s",
|
||||
"horizon.pack.addInfo": "Lisage Modrinthist ressursipakett",
|
||||
"horizon.pack.addWorking": "Modrinthilt küsides...",
|
||||
"horizon.pack.addNone": "Ressursipakette ei leitud",
|
||||
"horizon.pack.addTitle": "Lisage ressursipakett",
|
||||
"horizon.pack.install": "Installige",
|
||||
"horizon.pack.installing": "Paigaldamine",
|
||||
"horizon.pack.installed": "Paigaldatud",
|
||||
"horizon.pack.search": "Otsi",
|
||||
"horizon.pack.searchHint": "Otsi Modrinthist...",
|
||||
"horizon.pack.filters": "Filtrid",
|
||||
"horizon.pack.filter.realistic": "Realistlik",
|
||||
"horizon.pack.filter.simplistic": "Lihtsustatud",
|
||||
"horizon.pack.filter.vanillaLike": "Vaniljelaadne",
|
||||
"horizon.pack.addFailed": "Pakki ei saanud lisada: %s",
|
||||
"horizon.extras.header.cosmetics": "Kosmeetika",
|
||||
"horizon.extras.cosmetics_mine": "Minu kosmeetika",
|
||||
"horizon.extras.cosmetics_mine.tooltip": "Varjatud: iga Horizoni mängija näeb teid ilma teie kosmeetikata, kaasa arvatud. Sama lüliti, mis käivitaja riidekapil.",
|
||||
"horizon.extras.cosmetics_others": "Teiste mängijate kosmeetika",
|
||||
"horizon.extras.cosmetics_others.tooltip": "Mida teised Horizoni mängijad kannavad: kõike, ainult nende nimesiltide stiile või mitte midagi. Varjatud, mäng ei küsi kunagi, mida nad kannavad.",
|
||||
"horizon.extras.cosmetics_auras": "Teiste aurad ja jäljed",
|
||||
"horizon.extras.cosmetics_auras.tooltip": "Aurad ja jäljed, mida teised mängijad kannavad. Vaikimisi väljas.",
|
||||
"horizon.extras.cosmetics.shown": "Näidatud",
|
||||
"horizon.extras.cosmetics.hidden": "Peidetud",
|
||||
"horizon.extras.cosmetics.name_tags": "Ainult nimesildid"
|
||||
}
|
||||
@@ -0,0 +1,476 @@
|
||||
{
|
||||
"horizon.options.controller": "Kontrolatzailea",
|
||||
"horizon.options.vibration": "Dardara",
|
||||
"horizon.options.adaptive_triggers": "Abiarazle moldagarriak",
|
||||
"horizon.options.lightbar": "Argi-barra",
|
||||
"horizon.options.look_sensitivity": "Begiradaren sentikortasuna",
|
||||
"horizon.options.invert_x": "Begirada X alderantzikatua",
|
||||
"horizon.options.invert_y": "Begirada Y alderantzikatua",
|
||||
"horizon.options.sneak_button": "Makurtzeko botoia",
|
||||
"horizon.options.move_deadzone": "Mugimenduaren zona hila",
|
||||
"horizon.options.look_deadzone": "Begiradaren zona hila",
|
||||
"horizon.options.button_glyphs": "Botoien glifoak",
|
||||
"horizon.options.on_screen_keyboard": "Pantailako teklatua",
|
||||
"horizon.options.chat_delay": "Txat-atzerapena",
|
||||
"horizon.options.lightbar.health": "Osasuna",
|
||||
"horizon.options.lightbar.dimension": "Dimentsioa",
|
||||
"horizon.options.glyphs.auto": "Autoa",
|
||||
"horizon.options.keyboard.auto": "Autoa",
|
||||
"horizon.options.unavailable": "Eginbide hau oraindik ez dago erabilgarri Horizon-n.",
|
||||
"horizon.options.search": "Bilaketa-ezarpenak...",
|
||||
"horizon.pages.mods": "Moduak",
|
||||
"horizon.pages.shader_packs": "Shader paketeak",
|
||||
"horizon.pages.shader_options": "Itzalaren aukerak",
|
||||
"horizon.pages.controller": "Kontrolagailuaren ezarpenak",
|
||||
"horizon.pages.controller_binds": "Kontrolatzaileak lotzen ditu",
|
||||
"horizon.pages.extras": "Horizon Gehigarriak",
|
||||
"horizon.pages.settings": "Horizon Ezarpenak",
|
||||
"horizon.pages.agent": "AI agentea",
|
||||
"horizon.split.leave": "Utzi",
|
||||
"horizon.pages.split_settings": "Pantaila zatituko ezarpenak",
|
||||
"horizon.pages.split_profiles": "Nor ari da jolasten?",
|
||||
"horizon.pages.split_setup": "Pantaila zatituaren konfigurazioa",
|
||||
"horizon.pages.music": "Musika",
|
||||
"horizon.pages.music.menu": "Menua",
|
||||
"horizon.pages.music.creative": "Sortzailea",
|
||||
"horizon.pages.music.underwater": "Urpean",
|
||||
"horizon.pages.music.end": "Amaiera",
|
||||
"horizon.pages.music.boss": "Nagusia",
|
||||
"horizon.pages.music.credits": "Kredituak",
|
||||
"horizon.pages.music.overworld_biomes": "Overworld biomak",
|
||||
"horizon.pages.music.nether_biomes": "Beheko biomak",
|
||||
"horizon.pages.music.end_biomes": "Amaiera biomak",
|
||||
"horizon.pages.music.other": "Beste musika batzuk",
|
||||
"horizon.pages.music.empty": "Ez dago musika pistarik: jokoaren soinuak ez dira kargatzen.",
|
||||
"horizon.pages.music.tooltip": "Inkorporatutako pistak, egoeraren arabera: jokatu bat orain edo desaktibatu beste bat, jokoak hautatzeari uzteko.",
|
||||
"horizon.pages.settings.tooltip": "Horizonren ezarpenak: grafikoak, kontrolagailuak, gehigarriak eta modak.",
|
||||
"horizon.pages.graphics.tooltip": "Grafikoak, besterik gabe: ezarpen bakoitzak zer balio duen esaten du.",
|
||||
"horizon.pages.graphics_advanced.tooltip": "Ezarpen grafiko bakoitza, Horizon barne, bakoitzak balio duenarekin.",
|
||||
"horizon.pages.controller.tooltip": "Kontrolagailuak: haien botoiak, makilak, bibrazioa eta menuen nabigazioa.",
|
||||
"horizon.pages.extras.tooltip": "Aukerako gehigarriak, guztiak lehenespenez desaktibatuta: jokoak bainila izaten jarraitzen du bat aktibatu arte.",
|
||||
"horizon.pages.agent.tooltip": "Utzi zure AI agentea jolasten: horizon-ctl eta MCP bezeroak ordenagailu honetan.",
|
||||
"horizon.pages.split_profiles.tooltip": "Nork jokatzen du: jokoaren karpeta honetan gordetako profila.",
|
||||
"horizon.pages.split_setup.tooltip": "Leihoak eta monitoreak, eta nork jokatzen duen non.",
|
||||
"horizon.pages.shader_packs.tooltip": "Shader-paketeak shaderpacks karpetatik: Horizon bereak eta shaders/ formatuan daudenak. Bat aldi berean korrika.",
|
||||
"horizon.pages.mods.tooltip": "Horizon-rako egindako modak, horizon-mods karpetatik. Bakoitza sandbox batean exekutatzen da eta itzalita geratzen da pizten duzun arte.",
|
||||
"horizon.pages.open.graphics": "Grafikoak...",
|
||||
"horizon.pages.open.graphics_advanced": "Grafiko aurreratuak...",
|
||||
"horizon.pages.open.shader_packs": "Shader paketeak...",
|
||||
"horizon.pages.open.controller": "Kontrolagailuaren ezarpenak...",
|
||||
"horizon.pages.open.split_setup": "Pantaila zatitua...",
|
||||
"horizon.pages.open.extras": "Gehigarriak...",
|
||||
"horizon.pages.open.mods": "Moduak...",
|
||||
"horizon.pages.open.agent": "AI agentea...",
|
||||
"horizon.pages.open.horizon_graphics": "Horizon Grafikoak...",
|
||||
"horizon.pages.open.controller_binds": "Kontrolagailua lotzen da...",
|
||||
"horizon.pages.open.horizon_settings": "Horizon Ezarpenak...",
|
||||
"horizon.pages.open.music": "Musika...",
|
||||
"horizon.mods.empty": "Modrik ez: jarri .hmod fitxategiak horizon-mods karpetan",
|
||||
"horizon.mods.stopped": " (Gelditu)",
|
||||
"horizon.mods.not_built": " (Ez eraikia)",
|
||||
"horizon.mods.dev": " (Garapena)",
|
||||
"horizon.mods.settings": "Ezarpenak",
|
||||
"horizon.mods.in_world": " (utzi mundua aldatzen)",
|
||||
"horizon.mods.open_folder": "Ireki Mod karpeta",
|
||||
"horizon.shader_packs.empty": "Ez dago itzal-paketerik: jarri itzazu itzal-paketeen karpetan",
|
||||
"horizon.shader_options.open": "Itzalaren aukerak...",
|
||||
"horizon.shader_options.profile": "Profila",
|
||||
"horizon.shader_options.loading": "Shader paketearen aukerak irakurtzen...",
|
||||
"horizon.agent.copy_details": "Kopiatu konexioaren xehetasunak",
|
||||
"horizon.multiplayer.join": "Sartu",
|
||||
"horizon.multiplayer.cancel_reconnecting": "Utzi berriro konektatzea",
|
||||
"horizon.multiplayer.join_friend": "Sartu Lagun batekin",
|
||||
"horizon.multiplayer.invite_code": "Gonbidatu kodea",
|
||||
"horizon.multiplayer.relay": "Erreleboa (aukerakoa)",
|
||||
"Preset": "Aurrez ezarritakoa",
|
||||
"LOD Distance": "LOD Distantzia",
|
||||
"Far Detail": "Urruneko xehetasuna",
|
||||
"Cave Culling": "Haitzuloen Mozketa",
|
||||
"Entity Culling": "Entitatea Kulling",
|
||||
"Chunk Updates": "Chunk eguneraketak",
|
||||
"Upload Budget": "Kargatu Aurrekontua",
|
||||
"Sky": "Zerua",
|
||||
"Fog": "Lainoa",
|
||||
"Weather": "Eguraldia",
|
||||
"Animated Textures": "Ehundura animatuak",
|
||||
"Present Mode": "Oraingo Modua",
|
||||
"Frame Pacing": "Markoaren erritmoa",
|
||||
"Worker Threads": "Langileen hariak",
|
||||
"Resolution Scale": "Ebazpen Eskala",
|
||||
"Anti-aliasing": "Aliasaren aurkakoa",
|
||||
"Upscaling": "Handitzea",
|
||||
"Paper White": "Paper Zuria",
|
||||
"Peak Brightness": "Distira gailurra",
|
||||
"Black Level": "Beltza Maila",
|
||||
"UI Brightness": "Interfazearen distira",
|
||||
"Battery Mode": "Bateria modua",
|
||||
"Graphics API": "Grafikoen APIa",
|
||||
"Translucent Batching": "Lote zeharrargitsua",
|
||||
"Full Detail Distance": "Xehetasun osoa Distantzia",
|
||||
"Off": "Desaktibatuta",
|
||||
"Unlimited": "Mugagabea",
|
||||
"Auto": "Autoa",
|
||||
"Custom": "Pertsonalizatua",
|
||||
"Performance": "Errendimendua",
|
||||
"Balanced": "Orekatua",
|
||||
"Quality": "Kalitatea",
|
||||
"Native": "Jatorrizkoa",
|
||||
"Full": "Osoa",
|
||||
"Reduced": "Murriztua",
|
||||
"Efficient": "Eraginkorra",
|
||||
"Precise": "Zehatza",
|
||||
"Auto (VSync)": "Automatikoa (VSync)",
|
||||
"Mailbox": "Postontzia",
|
||||
"Immediate": "Berehala",
|
||||
"FPS and Graph": "FPS eta grafikoa",
|
||||
"No cost": "Ez dago kosturik",
|
||||
"Low cost": "Kostu baxua",
|
||||
"Medium cost": "Kostu ertaina",
|
||||
"High cost": "Kostu handia",
|
||||
"Saves time": "Denbora aurrezten du",
|
||||
"Graphics": "Grafikoak",
|
||||
"Done": "Eginda",
|
||||
"This feature is not yet available in Horizon.": "Eginbide hau oraindik ez dago erabilgarri Horizon-n.",
|
||||
"Your display or system doesn't offer HDR output.": "Zure pantailak edo sistemak ez du HDR irteerarik eskaintzen.",
|
||||
"Turn HDR on to use it.": "Aktibatu HDR hura erabiltzeko.",
|
||||
"Your GPU or graphics API doesn't support it.": "Zure GPU edo grafikoen APIak ez du onartzen.",
|
||||
"%s chunks": "%s puskak",
|
||||
"%s per frame": "%s fotograma bakoitzeko",
|
||||
"%s MiB/frame": "%s MiB/markoa",
|
||||
"%s KiB/frame": "%s KiB/markoa",
|
||||
"Full-detail terrain range. LOD Distance can extend local worlds farther.": "Xehetasun osoko lur eremua. LOD Distantziak tokiko munduak urrunago heda ditzake.",
|
||||
"Coarse distant terrain in local worlds. Integrated GPUs stop at 128 chunks.": "Urruneko lur lodia tokiko munduetan. GPU integratuak 128 zatitan gelditzen dira.",
|
||||
"Reduced draws far terrain coarser: faster on this integrated GPU.": "Marrazki murrizketak lur urrunago lodiagoak: azkarrago GPU integratu honetan.",
|
||||
"Reduced draws far terrain coarser, for GPUs it slows down.": "Marrazki murriztuak lur urrunago lodiagoak dira, GPUentzat moteldu egiten da.",
|
||||
"Field of view. Wider shows more terrain at once.": "Ikus-eremua. Zabalerak lur gehiago erakusten du aldi berean.",
|
||||
"Caps frames per second; a cap saves power and heat.": "Maiuskulak segundoko fotogramak; txano batek energia eta beroa aurrezten ditu.",
|
||||
"Waits for the display's refresh: no tearing, a little latency.": "Pantaila freskatzeko zain dago: urratu gabe, latentzia pixka bat.",
|
||||
"Size of menus and the HUD.": "Menuen tamaina eta HUD-a.",
|
||||
"Sets the options below together. Changing one makes it Custom.": "Beheko aukerak batera ezartzen ditu. Bat aldatzeak pertsonalizatu egiten du.",
|
||||
"Lava, fire and sunlight shine brighter than white. Needs an HDR display.": "Labak, suak eta eguzki-argiak zuriak baino distira handiagoa dute. HDR pantaila bat behar du.",
|
||||
"Your display's darkest black. 0 for OLED; LCDs glow a little.": "Zure pantailako beltz ilunena da. 0 OLEDrako; LCDek apur bat distira egiten dute.",
|
||||
"How bright highlights get. Auto: the peak your system reports.": "Nola distiratsuak diren argiak. Auto: zure sistemak ematen duen gailurra.",
|
||||
"How bright white paper and menus look. Auto: your desktop's white.": "Zein itxura duten paper zuriak eta menuak. Auto: zure mahaigaina zuria da.",
|
||||
"How bright the HUD and menus are, against paper white.": "Zein distiratsuak diren HUD eta menuak, paper zuriaren aurka.",
|
||||
"How far mobs, crops and machines keep working. CPU time.": "Noraino jarraitzen duten mafiak, laboreak eta makinak lanean. CPU denbora.",
|
||||
"How far away mobs and items are drawn, as a share of normal.": "Noraino ateratzen diren mobs eta elementuak, normalaren zati gisa.",
|
||||
"Skips terrain hidden behind closed sections. Off costs a lot.": "Sekzio itxien atzean ezkutatuta dagoen lurra saltatzen du. Off asko kostatzen da.",
|
||||
"Hides entities behind opaque blocks.": "Bloke opakuen atzean dauden entitateak ezkutatzen ditu.",
|
||||
"No entity occlusion culling.": "Ez dago entitateen oklusioa kulling.",
|
||||
"CPU occlusion test runs this frame.": "PUZaren oklusioaren probak marko hau exekutatzen du.",
|
||||
"Occlusion checks run on a worker thread.": "Oklusio-egiaztapenak langile-hari batean exekutatzen dira.",
|
||||
"Meshed sections uploaded per frame. Lower is smoother while loading.": "Sareko atalak fotograma bakoitzeko kargatu dira. Behea leunagoa da kargatzean.",
|
||||
"Soft shadows in corners. Costs chunk building time only.": "Itzal leunak bazterretan. Eraikitzeko denbora zati bat bakarrik kostatzen du.",
|
||||
"Smaller copies of block textures for distant terrain: less shimmer.": "Bloke-ehunduraren kopia txikiagoak lur urrunetarako: distira gutxiago.",
|
||||
"Blends grass and water colours across biomes when building chunks.": "Belarra eta ur koloreak nahasten ditu biometan zatiak eraikitzean.",
|
||||
"Cloud layer: off, flat (fast) or 3D (fancy).": "Hodei geruza: desaktibatuta, laua (bizkorra) edo 3D (fantastikoa).",
|
||||
"How far clouds reach, in chunks.": "Noraino iristen diren hodeiak, zatika.",
|
||||
"Draws the sky, sun, moon and stars.": "Zerua, eguzkia, ilargia eta izarrak marrazten ditu.",
|
||||
"Distance fog. Off shows the edge of the loaded world.": "Distantzia lainoa. Off mundu kargatuaren ertza erakusten du.",
|
||||
"Draws rain and snow.": "Euria eta elurra marrazten ditu.",
|
||||
"How far rain and snow fall around you.": "Noraino erortzen diren euria eta elurra zure inguruan.",
|
||||
"How many particles effects spawn.": "Zenbat partikulen eraginak sortzen diren.",
|
||||
"Round shadows under mobs and items.": "Itzal biribilak mob eta elementuen azpian.",
|
||||
"Leaves with see-through gaps. Off draws them solid.": "Hutsune ikusgarriak dituzten hostoak. Off-ek sendo marrazten ditu.",
|
||||
"Sorts water and glass more exactly behind each other.": "Ura eta beira bata bestearen atzetik zehatzago sailkatzen ditu.",
|
||||
"Which chunk rebuilds wait for the frame: none, nearby or yours.": "Zein zati berreraikitzen den markoaren zain: bat ere ez, gertukoa edo zurea.",
|
||||
"Animates water, lava, fire and other moving textures.": "Ura, laba, sua eta beste ehundura mugikor batzuk animatzen ditu.",
|
||||
"World pixels per screen pixel. Below 100% is faster on the GPU.": "Munduko pixelak pantailako pixel bakoitzeko. % 100etik behera azkarragoa da GPUan.",
|
||||
"Smooths jagged edges. FXAA: softer. TAA: smoothest, moving things may trail.": "Ertz bitxiak leuntzen ditu. FXAA: bigunagoa. TAA: leunena, mugitzen diren gauzak atzetik joan daitezke.",
|
||||
"Renders the world smaller and rebuilds it with TAA. Faster, softer.": "Mundua txikiagotzen du eta TAArekin berreraikitzen du. Azkarrago, leunagoa.",
|
||||
"HDR output on an HDR display: lava, fire and sunlight shine brighter.": "HDR irteera HDR pantaila batean: labak, sua eta eguzki-argiak distiratsuagoak dira.",
|
||||
"How frames reach the screen while VSync is off.": "Nola iristen diren fotogramak pantailara VSync itzalita dagoen bitartean.",
|
||||
"Efficient sleeps until the next frame; Precise spins, like vanilla.": "Lo eraginkorra hurrengo fotograma arte; Bira zehatzak, bainila bezala.",
|
||||
"Fills the screen (borderless).": "Pantaila betetzen du (ertzak gabe).",
|
||||
"Brightens dark places.": "Leku ilunak argitzen ditu.",
|
||||
"Lowers the frame rate when minimised, or idle too.": "Fotograma-abiadura murrizten du minimizatzen denean, edo inaktibo ere.",
|
||||
"Sways the view while walking.": "Ikuspegia aldarazi egiten du oinez ibiltzean.",
|
||||
"Fades newly loaded chunks in.": "Kargatutako zati berriak lausotzen ditu.",
|
||||
"Darkens the screen's edges.": "Pantailaren ertzak iluntzen ditu.",
|
||||
"Shows when the world saves.": "Munduak salbatzen duenean erakusten du.",
|
||||
"Shows attack cooldown.": "Erasoaren hoztea erakusten du.",
|
||||
"60 FPS cap (30 in menus or unfocused), half the workers: less power.": "60 FPS muga (30 menuetan edo fokatu gabe), langileen erdia: potentzia gutxiago.",
|
||||
"Threads that generate, light and mesh chunks. Next start.": "Sortzen dituzten hariak, zati argiak eta sareak. Hurrengo hasiera.",
|
||||
"Vulkan, then DirectX 12 (Windows) or OpenGL (Linux) where it fails. Next start.": "Vulkan, gero DirectX 12 (Windows) edo OpenGL (Linux) non huts egiten duen. Hurrengo hasiera.",
|
||||
"Water and glass in one buffer: fewer draw calls, a bit more VRAM. Next start.": "Ura eta beira buffer batean: zozketa-dei gutxiago, VRAM pixka bat gehiago. Hurrengo hasiera.",
|
||||
"Mesh data sent to the GPU per frame. Lower is smoother while loading.": "GPUra bidalitako sareko datuak fotograma bakoitzeko. Behea leunagoa da kargatzean.",
|
||||
"Frame rate and frame times over the game, with a graph.": "Fotograma-tasa eta fotograma-denborak jokoan zehar, grafiko batekin.",
|
||||
"horizon.multiplayer.finding_friend": "Zure lagunaren mundua aurkitzen...",
|
||||
"horizon.multiplayer.not_signed_in": "Zerbitzari hau lineako moduan dago. Hasi saioa zure Microsoft kontuarekin Horizon abiarazlean bertan sartzeko.",
|
||||
"horizon.multiplayer.invalid_address": "Zerbitzariaren helbide baliogabea: %s",
|
||||
"horizon.multiplayer.connected_friend_direct": "Zure lagunarekin zuzenean konektatuta...",
|
||||
"horizon.multiplayer.connected_friend_relay": "Zure lagunarekin erreleboaren bidez konektatuta...",
|
||||
"General": "Orokorra",
|
||||
"Advanced": "Aurreratua",
|
||||
"Undo": "Desegin",
|
||||
"Search options": "Bilaketa aukerak",
|
||||
"Shortcut": "Lasterbidea",
|
||||
"Distance": "Distantzia",
|
||||
"Display": "Bistaratzea",
|
||||
"Interface": "Interfazea",
|
||||
"Sky and weather": "Zerua eta eguraldia",
|
||||
"Lighting and entities": "Argiztapena eta entitateak",
|
||||
"Textures": "Ehundurak",
|
||||
"Image": "Irudia",
|
||||
"Chunk loading": "Zati zatiak kargatzea",
|
||||
"Culling": "Mozketa",
|
||||
"Power": "Boterea",
|
||||
"Frames": "Markoak",
|
||||
"Overlay": "Gainjartzea",
|
||||
"Output": "Irteera",
|
||||
"Brightness": "Distira",
|
||||
"How far you see, the window and the HUD.": "Noraino ikusten duzun, leihoa eta HUD-a.",
|
||||
"The sky and weather, lighting, textures and the image.": "Zerua eta eguraldia, argia, testurak eta irudia.",
|
||||
"Chunk loading, culling and power use.": "Zama zatiak, mozketa eta energia erabiltzea.",
|
||||
"How frames reach the screen, and the performance overlay.": "Fotogramak pantailara nola iristen diren eta errendimenduaren gainjartzea.",
|
||||
"Brighter-than-white output on an HDR display.": "Irteera zuria baino distiratsuagoa HDR pantaila batean.",
|
||||
"Results for \"%s\"": "\"%s\" bilaketaren emaitzak",
|
||||
"No settings match.": "Ez dago ezarpenik bat.",
|
||||
"horizon.title.not_affiliated": "Ez dago Mojang edo Microsoft-ekin afiliatuta",
|
||||
"horizon.extras.header.lighting": "Argiztapena",
|
||||
"horizon.extras.header.third_person": "Hirugarren pertsona",
|
||||
"horizon.extras.header.particles": "Partikulak",
|
||||
"horizon.extras.header.inventory": "Inbentarioa",
|
||||
"horizon.extras.header.chat": "Txateatu",
|
||||
"horizon.extras.header.multiplayer": "Jokalari anitzekoa",
|
||||
"horizon.extras.header.sound": "Soinua",
|
||||
"horizon.extras.header.menus": "Menuak",
|
||||
"horizon.extras.fullbright": "Argi osoa",
|
||||
"horizon.extras.dynamic_lights": "Argi dinamikoak",
|
||||
"horizon.extras.own_name_tag": "Izen-etiketa propioa",
|
||||
"horizon.extras.hide_block_particles": "Ezkutatu bloke-hausturako partikulak",
|
||||
"horizon.extras.auto_reconnect": "Berriro konektatu automatikoki",
|
||||
"horizon.extras.ui_sound_reserve": "Mantendu kanalak UI soinuetarako",
|
||||
"horizon.extras.music_page": "Musika orria",
|
||||
"horizon.extras.mouse_tweaks": "Mouse Tweaks kontrolak",
|
||||
"horizon.extras.mouse_tweaks_wheel": "Korritzeko gurpilak elementuak mugitzen ditu",
|
||||
"horizon.extras.sort": "Ordenatzeko botoiak",
|
||||
"horizon.extras.sort_key": "Ordenatzeko tekla",
|
||||
"horizon.extras.no_ai": "AIrik ez",
|
||||
"horizon.extras.agent_control": "Agenteen Kontrola",
|
||||
"horizon.extras.discord_presence": "Discord Presentzia aberatsa",
|
||||
"horizon.extras.splitscreen": "Pantaila zatitua",
|
||||
"horizon.extras.chat_animation": "Txat leuna",
|
||||
"horizon.extras.chat_indicator": "Mezuen adierazlea",
|
||||
"horizon.extras.wheel_cycles_settings": "Korritzeko gurpilak ezarpenak aldatzen ditu",
|
||||
"horizon.extras.pack_browser": "Baliabide paketeen arakatzailea",
|
||||
"horizon.extras.fullbright.tooltip": "Erakutsi blokeak eta entitateak argi betean, baita eremu ilunetan ere.",
|
||||
"horizon.extras.dynamic_lights.tooltip": "Zuziak eta beste argi-iturri batzuk eusten, erorita edo sutan pizten dituzte inguruko blokeak.",
|
||||
"horizon.extras.own_name_tag.tooltip": "Zure izena zure buruaren gainean erakusten du hirugarren pertsonan, beste jokalariek ikusten duten moduan. Ezkutatuta dago zerbitzariak zure taldearen izenak ezkutatzen dituenean edo ikusezina zarenean.",
|
||||
"horizon.extras.hide_block_particles.tooltip": "Hautsitako bloke batetik lehertu eta mina duzuna erortzen diren hondakin-partikulak ezkutatzen ditu. Beste partikula batzuk geratzen dira.",
|
||||
"horizon.extras.auto_reconnect.tooltip": "Konexioa galdu edo berrabiarazi ondoren zerbitzari batean sartzen da berriro, inoiz ez ostiko bat edo debeku baten ondoren.",
|
||||
"horizon.extras.ui_sound_reserve.tooltip": "Munduko soinuek 247 soinu-kanaletatik 16 libre uzten dituzte, beraz, uholde batek (leherketa handi bat) ezin ditu menuko klikak isilarazi.",
|
||||
"horizon.extras.music_page.tooltip": "Music & Sounds-ek Musika... orria lortzen du: erreproduzitu integratutako edozein pista orain, edo desaktibatu bat jokoak hautatzeari uzteko. Ez da ezer aldatzen pista bat itzali arte.",
|
||||
"horizon.extras.mouse_tweaks.tooltip": "Eskuinean arrastatu sakatuta bat jartzen du zirrikitu bakoitzeko, ezkerrean arrastatu edukitako elementua biltzen du, Maius + ezkerrera arrastatu zirrikitu guztiak mugitzen ditu.",
|
||||
"horizon.extras.mouse_tweaks_wheel.tooltip": "Beherak zirrikituaren elementu bat beste aldera bidaltzen du, gorak bat itzultzen du.",
|
||||
"horizon.extras.sort.tooltip": "Inbentarioa, kutxak, upelak, ender kutxak eta shulker-kutxak sortze-ordenan ordenatzen ditu, pilak batuz.",
|
||||
"horizon.extras.sort_key.tooltip": "Kurtsorea azpian dagoen zatia ordenatzen du. Egin klik, eta sakatu tekla bat; Ihesak askatzen du.",
|
||||
"horizon.extras.no_ai.tooltip": "AI funtzio guztiak ezkutatu eta desaktibatu egiten ditu: agenteen kontrola, horizon-ctl eta MCP zerbitzariak. Abiarazlearen etengailua ere.",
|
||||
"horizon.extras.agent_control.tooltip": "Zure AI agenteak horizon-ctl edo MCP bezero baten bidez jolastu dezake joko honetara, ordenagailu honetan soilik.",
|
||||
"horizon.extras.discord_presence.tooltip": "Discord exekutatzen den bitartean Horizon Jolasean erakusten du: menuak, jokalari bakarreko edo jokalari anitzeko, dimentsioa eta jokatutako denbora. Inoiz ez mundu baten izenik edo zerbitzari baten helbidea.",
|
||||
"Calibrate...": "Kalibratu...",
|
||||
"Calibrate Anyway...": "Kalibratu Dena den...",
|
||||
"Use Automatic Setup": "Erabili konfigurazio automatikoa",
|
||||
"Shortcut: %s": "Lasterbidea: %s",
|
||||
"Next": "Hurrengoa",
|
||||
"HDR Calibration %s/%s: %s": "HDR Kalibrazioa %s/%s: %s",
|
||||
"Sets the three below full screen, one test picture at a time.": "Pantaila osoko azpian dauden hiru ezartzen ditu, probako argazki bat aldi berean.",
|
||||
"A key that opens this screen from the game. Not bound at first.": "Pantaila hau jokotik irekitzen duen giltza. Hasieran lotu gabe.",
|
||||
"Your display didn't say how bright it gets: calibrate to set it up.": "Pantailak ez du esan zenbat argi dagoen: kalibratu konfiguratzeko.",
|
||||
"Already set up for your display. Only calibrate if HDR looks wrong.": "Dagoeneko konfiguratuta zaude zure pantailarako. Kalibratu HDR okerra bada bakarrik.",
|
||||
"Puts Peak Brightness and Paper White back to your display's setup.": "Distira gailurra eta Paper Zuria berriro jartzen ditu pantailaren konfiguraziora.",
|
||||
"Set up for your display. Leave on Auto unless it looks wrong.": "Konfiguratu zure pantailarako. Utzi automatikoa aktibatuta, gaizki ikusten ez bada.",
|
||||
"Lower it until the logo just disappears into the black.": "Jaitsi logoa beltzean desagertu arte.",
|
||||
"Raise it until the logo just disappears into the bright square.": "Altxa ezazu logotipoa karratu distiratsuan desagertu arte.",
|
||||
"Make the card a white that's comfortable to look at for a long time, in the light you play in.": "Egin ezazu txartela denbora luzez begiratzeko erosoa den zuria, jolasten duzun argitan.",
|
||||
"horizon.splitscreen.profiles.forget": "Ahaztu",
|
||||
"horizon.splitscreen.profiles.create": "Sortu",
|
||||
"horizon.splitscreen.profiles.you": " - zu",
|
||||
"horizon.splitscreen.profiles.forget_named": "Ahaztu %s",
|
||||
"horizon.splitscreen.profiles.previous": "Aurrekoa",
|
||||
"horizon.splitscreen.profiles.next": "Hurrengoa",
|
||||
"horizon.splitscreen.profiles.new_button": "Profil berria...",
|
||||
"horizon.splitscreen.profiles.forget_title": "Profila ahaztu?",
|
||||
"horizon.splitscreen.profiles.forget_leaves": "Instantzia honen zerrenda uzten du.",
|
||||
"horizon.splitscreen.profiles.forget_kept": "Munduko aurrerapena eta ezarpenak mantentzen dira.",
|
||||
"horizon.splitscreen.profiles.new_title": "Profil berria",
|
||||
"horizon.splitscreen.profiles.name_hint": "Izena (3 eta 16 letra, zifra, _)",
|
||||
"horizon.splitscreen.profiles.switch_title": "Aldatu profila",
|
||||
"horizon.splitscreen.profiles.offline_note": "Lineaz kanpoko profilak instantzia honetakoak dira",
|
||||
"horizon.splitscreen.profiles.move": "Mugitu jolasten duzun tokira",
|
||||
"horizon.splitscreen.profiles.move_place": "Mugitu jolasten duzun tokira: %s",
|
||||
"horizon.friends.title": "Jolastu Lagunekin",
|
||||
"horizon.friends.hint": "Lagunek itsatsi dute kodea izenburu-pantailaren Lagunak botoian, Zuzeneko konexioan edo abiarazlearen Play orrian.",
|
||||
"horizon.friends.copied": "Kopiatua",
|
||||
"horizon.friends.copy_code": "Kopiatu kodea",
|
||||
"horizon.friends.stop_sharing": "Utzi partekatzeari",
|
||||
"horizon.friends.none_yet": "Hemen oraindik ez dago lagunik.",
|
||||
"horizon.friends.here_now": "Hemen orain: %s",
|
||||
"horizon.friends.share_intro": "Partekatu mundu hau gonbidapen-kode baten atzean: LANera irekitzen da eta Interneteko lagunak bat egiten dute kodearekin. Ez dago gure zerbitzaririk parte hartzen.",
|
||||
"horizon.friends.start_sharing": "Hasi Partekatzen",
|
||||
"horizon.friends.troubleshooting": "Arazoak konpontzen...",
|
||||
"horizon.friends.stopped": "Gonbidapen kodea partekatzeari utzi dio.",
|
||||
"horizon.friends.short_code_changed": "Norbaitek kode labur oker bat probatzen jarraitu zuen, beraz, aldatu egin zen.",
|
||||
"horizon.friends.wrong_code": "Norbaitek kode oker batekin saiatu da.",
|
||||
"horizon.friends.code_ready": "Zure gonbidapen-kodea prest dago: Jokoen menua, Jolastu lagunekin. Kopiatu eta bidali zure lagunei.",
|
||||
"horizon.friends.share_failed": "Ezin izan da mundua partekatu: %s",
|
||||
"horizon.friends.finding_route": "Lagunak zurekin nola irits daitezkeen aurkitzen...",
|
||||
"horizon.osk.shift": "Txanda",
|
||||
"horizon.osk.space": "Espazioa",
|
||||
"horizon.osk.delete": "Ezabatu",
|
||||
"horizon.osk.type": "Mota",
|
||||
"horizon.osk.symbols": "Sinboloak",
|
||||
"horizon.osk.close": "Itxi",
|
||||
"horizon.extras.chat_animation.tooltip": "Txat-lerro berri bat ezkerretik sartzen da desagertzen den bitartean, osorik agertu beharrean.",
|
||||
"horizon.extras.chat_indicator.tooltip": "Txat-lerro baten ezkerreko koloretako barra.",
|
||||
"horizon.extras.wheel_cycles_settings.tooltip": "Ezarpenetako botoi baten gainean korritzeko gurpilak bere balioa aldatzen du, bainilan bezala. Desaktibatuta, gurpilak zerrendan bakarrik mugitzen du.",
|
||||
"horizon.extras.pack_browser.tooltip": "Aukeratu Baliabide Paketeak Gehitu botoi bat lortzen du, Modrinth bilatzen duena eta pakete bat instalatzen du zure paketeen karpetan. Desaktibatuta, jokoa ez da inoiz Modrinth-ekin harremanetan jartzen.",
|
||||
"horizon.extras.splitscreen.tooltip": "Mundu batean, beste kontrolagailu bat sar daiteke jokalari berri gisa: sakatu A eskatzen dionean, eta hautatu profil bat eta non jokatu.",
|
||||
"horizon.splitscreen.setup.monitor": "Monitorea %s",
|
||||
"horizon.splitscreen.setup.monitor_unknown": "monitore bat",
|
||||
"horizon.splitscreen.setup.window": "%s leihoa",
|
||||
"horizon.splitscreen.setup.new_window": "Leiho berria",
|
||||
"horizon.splitscreen.setup.fill_monitor": "Bete %s",
|
||||
"horizon.splitscreen.setup.done": "Eginda",
|
||||
"horizon.splitscreen.setup.off": "Desaktibatuta",
|
||||
"horizon.splitscreen.setup.player": "Jokalari %s",
|
||||
"horizon.splitscreen.setup.revert": "Atzera",
|
||||
"horizon.splitscreen.setup.apply": "Aplikatu",
|
||||
"horizon.splitscreen.setup.warning.empty_main": "Inork ez du jolasten Window 1-n: ezkutatzen da",
|
||||
"horizon.splitscreen.setup.warning.empty_close": "Inork ez du jolasten %s leihoan: Aplikatuan ixten da",
|
||||
"horizon.splitscreen.setup.warning.empty_new": "Inork ez du jolasten %s leihoan: ez da irekiko",
|
||||
"horizon.splitscreen.setup.warning.on_main": "%s leihoak 1. leihoaren monitorea betetzen du: bere jokalariek 1. leihoan jokatzen dute",
|
||||
"horizon.splitscreen.setup.warning.unplugged": "%s leihoaren monitorea ez dago konektatuta: bere jokalariek 1. leihoan jokatzen dute",
|
||||
"horizon.splitscreen.setup.status.off": "Pantaila zatitua itzalita dago.",
|
||||
"horizon.splitscreen.setup.status.enable_hint": "Piztu eta sakatu mundu bateko beste kontrolagailu bateko botoi bat.",
|
||||
"horizon.splitscreen.setup.status.join_hint": "Sakatu A sartzeko eta profil bat hautatzeko.",
|
||||
"horizon.splitscreen.setup.status.idle": "Pantaila zatitua inaktibo",
|
||||
"horizon.splitscreen.setup.status.alone": "Bertako beste jokalaririk ez.",
|
||||
"horizon.splitscreen.setup.status.solo_controls": "Bakarkako kontrolak eta kontroladorearen feedbacka ez dira aldatu.",
|
||||
"horizon.splitscreen.setup.window_empty": "%s leihoa: hutsik",
|
||||
"horizon.splitscreen.setup.note.select": "Egin klik erreproduzitzaile batean, edo arrastatu leiho batera edo monitore batera.",
|
||||
"horizon.splitscreen.setup.note.apply": "Aplikatu modu honetan erreproduzitzeko, itzuli desegin egiteko.",
|
||||
"horizon.splitscreen.setup.note.place": "Non jokatu behar du %s?",
|
||||
"horizon.splitscreen.setup.this_player": "jokalari hau",
|
||||
"horizon.splitscreen.setup.switch_disabled": "Pantaila zatitua itzaltzen da besteek irten direnean (haien eten menua).",
|
||||
"horizon.splitscreen.setup.window_place": "%s leihoa (%s/%s)",
|
||||
"horizon.splitscreen.setup.names": "Izenak",
|
||||
"horizon.splitscreen.setup.identify": "Identifikatu",
|
||||
"horizon.splitscreen.setup.layout.two": "2 partekatzea: %s",
|
||||
"horizon.splitscreen.setup.layout.three": "3 partekatzea: %s",
|
||||
"horizon.splitscreen.setup.layout.two.0": "Autoa",
|
||||
"horizon.splitscreen.setup.layout.two.1": "Elkarren ondoan",
|
||||
"horizon.splitscreen.setup.layout.two.2": "Goian eta behean",
|
||||
"horizon.splitscreen.setup.layout.three.0": "Bat zabal gainean",
|
||||
"horizon.splitscreen.setup.layout.three.1": "Altuera bat ezkerraldean",
|
||||
"horizon.splitscreen.setup.layout.three.2": "Elkarren ondoan",
|
||||
"horizon.splitscreen.setup.help.player": "Egin klik edo arrastatu %s horiek mugitzeko.",
|
||||
"horizon.splitscreen.setup.help.layout_auto": "%s (leihoa zabala denean elkarren ondoan). Sakatu aldatzeko.",
|
||||
"horizon.splitscreen.setup.help.layout": "%s. Sakatu aldatzeko.",
|
||||
"horizon.splitscreen.setup.help.switch": "Ordenagailu honen pantaila zatitua, piztuta edo itzalita.",
|
||||
"horizon.splitscreen.setup.help.identify": "Jokalari bakoitzaren ikuspegiak zein leihotan dagoen erakusten du.",
|
||||
"horizon.splitscreen.setup.help.names": "Jokalari bakoitzaren izena bere ikuspegiaren izkinan.",
|
||||
"horizon.splitscreen.setup.help.revert": "Desegin oraindik aplikatu gabeko aldaketak.",
|
||||
"horizon.splitscreen.setup.help.apply": "Erreproduzitu mapak erakusten duen moduan.",
|
||||
"horizon.splitscreen.setup.help.unchanged": "Oraindik ez da ezer aldatu.",
|
||||
"horizon.splitscreen.setup.give_up_pad": "Eman Pad",
|
||||
"horizon.splitscreen.prompt.controller_connected": "Kontroladorea konektatuta",
|
||||
"horizon.splitscreen.prompt.controller_disconnected": "Kontrolagailua deskonektatuta dago",
|
||||
"horizon.splitscreen.prompt.controller_disconnected.hint": "Konektatu berriro edo sakatu beste botoi bat",
|
||||
"horizon.splitscreen.prompt.join.one": "%s sartu nahi du",
|
||||
"horizon.splitscreen.prompt.join.many": "%s kontrolatzaileek sartu nahi dute",
|
||||
"horizon.splitscreen.prompt.join.yes": "Sartu",
|
||||
"horizon.splitscreen.prompt.join.as_p1": "Jokatu P1 bezala",
|
||||
"horizon.splitscreen.prompt.join.no": "Ez",
|
||||
"horizon.splitscreen.prompt.lost": "%s: kontrolagailua deskonektatuta dago",
|
||||
"horizon.splitscreen.prompt.lost.use_another": "Erabili beste bat",
|
||||
"horizon.splitscreen.prompt.lost.leave": "Utzi",
|
||||
"horizon.splitscreen.setup.help.give_up_pad": "Kontrolagailuak gidatzeari uzten dio eta sartzea eskaintzen zaio (A).",
|
||||
"horizon.splitscreen.setup.note.held_at": "%sri %sri: A-k hemen erortzen du, B-k berriro jartzen du.",
|
||||
"horizon.splitscreen.setup.note.held": "%s jasoa: ezkerrera/eskuinera hautatzen du non, A jaisten da, B-k berriro jartzen du.",
|
||||
"Hides models behind opaque blocks. Async checks off-thread; entities tick.": "Bloke opakuen atzean ereduak ezkutatzen ditu. Async egiaztapenak off-thread; entitateak markatuta.",
|
||||
"Block Entities": "Blokeatu Entitateak",
|
||||
"Shulker Boxes": "Shulker Kutxak",
|
||||
"Reuses settled boxes; lid movement stays animated.": "Kutxa finkatuak berrerabili; estalkien mugimendua animatuta geratzen da.",
|
||||
"Signs": "Seinaleak",
|
||||
"Reuses sign text until text, light, or font changes.": "Berrerabili zeinu-testua testua, argia edo letra-tipoa aldatu arte.",
|
||||
"Decorated Pots": "Pote apainduak",
|
||||
"Reuses still pots; break wobble and sherd changes redraw.": "Berrerabili oraindik lapikoak; hautsi wobble eta sherd aldaketak birmarraztu.",
|
||||
"Bells": "Kanpaiak",
|
||||
"Reuses still bells; ringing stays animated.": "Kanpai geldiak berrerabili; eraztunak animatuta geratzen dira.",
|
||||
"Chests": "Kutxak",
|
||||
"Reuses closed chests; moving lids stay animated.": "Itxitako kutxak berrerabili; mugitzen diren estalkiak animatuta geratzen dira.",
|
||||
"Banners": "Pankartak",
|
||||
"Reuses poles; flags and pattern layers still update.": "Zutoinak berrerabili; banderak eta eredu-geruzak oraindik eguneratzen dira.",
|
||||
"Copper Golem Statues": "Kobrezko Golem estatuak",
|
||||
"Reuses statue geometry until its block state changes.": "Estatuaren geometria berrerabili bere bloke-egoera aldatu arte.",
|
||||
"Leaf Culling": "Hosto-mozketa",
|
||||
"Every leaf face. Vanilla's fancy leaves.": "Hosto aurpegi bakoitza. Banilaren hosto dotoreak.",
|
||||
"Distant Plant Dither": "Urrutiko Landare Dither",
|
||||
"Keeps fine plants in high-res packs from fading far away.": "Erresoluzio handiko paketeetan landare finak urruti desager ez daitezen mantentzen du.",
|
||||
"Screenshot Quality": "Pantaila-argazkiaren kalitatea",
|
||||
"F2 screenshots at this many times the game's resolution. Higher takes longer.": "F2 pantaila-argazkiak jokoaren bereizmen askotan. Handiagoa denbora gehiago behar da.",
|
||||
"Frame Generation": "Frame Sorkuntza",
|
||||
"Shows a made-up frame between each two real ones: smoother, a little more lag.": "Bi erreal bakoitzaren artean osaturiko fotograma erakusten du: leunagoa, lag apur bat gehiago.",
|
||||
"Shadow Cache": "Itzalen cachea",
|
||||
"Reuses the pack shadow map when sun, view and world match. Off by default.": "Berrerabili paketearen itzal-mapa eguzkia, ikuspegia eta mundua bat datozenean. Desaktibatuta lehenespenez.",
|
||||
"Find BlueMap": "Bilatu BlueMap",
|
||||
"On servers, finds their BlueMap web map for far terrain. Next join.": "Zerbitzarietan, BlueMap web-mapa aurkitzen du urruneko lursailetarako. Hurrengoa sartu.",
|
||||
"BlueMap Radius": "BlueMap Erradioa",
|
||||
"How far around you BlueMap tiles are downloaded. Next join.": "Zure inguruan BlueMap fitxak deskargatzen diren noraino. Hurrengoa sartu.",
|
||||
"Synchronous": "Sinkronikoa",
|
||||
"Asynchronous": "Asinkronoak",
|
||||
"Solid": "Solidoa",
|
||||
"Solid Aggressive": "Solido Agresiboa",
|
||||
"Hollow": "Hutsak",
|
||||
"Leaves fully inside a canopy draw solid: fewer see-through layers.": "Hostoek erabat barnean marrazten dute koipea: geruza ikusgarri gutxiago.",
|
||||
"Leaves with one open side draw solid too: faster, chunkier edges.": "Alde bat irekita duten hostoek ere sendoak marrazten dituzte: ertz azkarragoak eta potoloagoak.",
|
||||
"Drops faces between leaves: faster, but gaps look through.": "Aurpegiak hostoen artean erortzen ditu: azkarrago, baina hutsuneak zeharkatzen ditu.",
|
||||
"Hotbar: Previous Slot": "Hotbar: Aurreko Slot",
|
||||
"Hotbar: Next Slot": "Hotbar: hurrengo zirrikitua",
|
||||
"horizon.agent.connected.one": "Konektatuta: agente konexio 1",
|
||||
"horizon.agent.connected.many": "Konektatuta: %s agente konexioak",
|
||||
"horizon.agent.connected.one_ago": "Konektatuta: 1 agente konexio, azken komandoa duela %s s",
|
||||
"horizon.agent.connected.many_ago": "Konektatuta: %s agente konexioak, duela %s azken komandoa",
|
||||
"horizon.agent.waiting": "Agente baten zain.",
|
||||
"horizon.agent.off": "Desaktibatuta: agenteak ezin dira joko honetara iritsi.",
|
||||
"horizon.agent.session_opened": "Saio honetarako irekia jokoa hasi zuen programak.",
|
||||
"horizon.agent.socket": "Socketa: %s (kopiatu bere bide osoaren xehetasunak)",
|
||||
"horizon.agent.local_only": "Tokiko soilik: ordenagailu honetako agenteak, inoiz ez sarekoak.",
|
||||
"Hides models behind opaque blocks. Entities update. Off with custom packs.": "Bloke opakuen atzean ereduak ezkutatzen ditu. Entitateak eguneratzea. Off pakete pertsonalizatuekin.",
|
||||
"horizon.extras.repro_keys": "Lasterbideak grabatzea",
|
||||
"horizon.extras.repro_keys.tooltip": "F3+R erreprodukzio-grabaketa bat hasten edo gelditzen da eta F3+E-k bere sorta idazten du. Desaktibatuta lehenespenez: grabazio batek mundua kopiatzen du.",
|
||||
"horizon.agent.record_session": "Hasi Grabaketa Saioa",
|
||||
"horizon.agent.record_stop": "Gelditu grabaketa saioa",
|
||||
"horizon.agent.export_repro": "Esportatu Repro sorta",
|
||||
"horizon.repro.started": "Grabaketa hasi zen; F3+R gelditu egiten da eta sorta idazten du.",
|
||||
"horizon.repro.stopped": "Grabaketa gelditu da: %s",
|
||||
"horizon.repro.bundle": "Erreprodukzio sorta: %s",
|
||||
"horizon.repro.error": "Erreprodukzioa: %s",
|
||||
"horizon.repro.no_recording": "Oraindik ez dago esportatzeko grabaziorik.",
|
||||
"horizon.repro.replay_started": "Erreprodukzioa hasi da: %s",
|
||||
"horizon.pack.addInfo": "Gehitu Modrinth-en baliabide-paketea",
|
||||
"horizon.pack.addWorking": "Modrinth galdetzen...",
|
||||
"horizon.pack.addNone": "Ez da aurkitu baliabide paketerik",
|
||||
"horizon.pack.addTitle": "Gehitu baliabide pakete bat",
|
||||
"horizon.pack.install": "Instalatu",
|
||||
"horizon.pack.installing": "Instalatzen",
|
||||
"horizon.pack.installed": "Instalatua",
|
||||
"horizon.pack.search": "Bilatu",
|
||||
"horizon.pack.searchHint": "Bilatu Modrinth...",
|
||||
"horizon.pack.filters": "Iragazkiak",
|
||||
"horizon.pack.filter.realistic": "Errealista",
|
||||
"horizon.pack.filter.simplistic": "Sinplista",
|
||||
"horizon.pack.filter.vanillaLike": "Banila itxurakoa",
|
||||
"horizon.pack.addFailed": "Ezin izan da paketea gehitu: %s",
|
||||
"horizon.extras.header.cosmetics": "Kosmetikoak",
|
||||
"horizon.extras.cosmetics_mine": "Nire kosmetikoak",
|
||||
"horizon.extras.cosmetics_mine.tooltip": "Ezkutuan: Horizon jokalari bakoitzak zure kosmetikarik gabe ikusten zaitu, zuk barne. Abiarazlearen armairuaren etengailu bera.",
|
||||
"horizon.extras.cosmetics_others": "Beste jokalarien kosmetika",
|
||||
"horizon.extras.cosmetics_others.tooltip": "Beste Horizon jokalariek zer janzten duten: denetarik, izenaren etiketa estiloak bakarrik, edo ezer ez. Ezkutuan, jokoak ez du inoiz galdetzen zer janzten duten.",
|
||||
"horizon.extras.cosmetics_auras": "Besteen aura eta ibilbideak",
|
||||
"horizon.extras.cosmetics_auras.tooltip": "Beste jokalariek janzten dituzten aura eta arrastoak. Desaktibatuta lehenespenez.",
|
||||
"horizon.extras.cosmetics.shown": "Erakutsita",
|
||||
"horizon.extras.cosmetics.hidden": "Ezkutuan",
|
||||
"horizon.extras.cosmetics.name_tags": "Izena etiketak soilik"
|
||||
}
|
||||
@@ -10,14 +10,11 @@
|
||||
"horizon.options.move_deadzone": "ناحیه مرده حرکت",
|
||||
"horizon.options.look_deadzone": "ناحیه مرده نگاه",
|
||||
"horizon.options.button_glyphs": "گلیف دکمه",
|
||||
"horizon.options.menu_navigation": "پیمایش منو",
|
||||
"horizon.options.on_screen_keyboard": "صفحه کلید روی صفحه",
|
||||
"horizon.options.chat_delay": "تاخیر چت",
|
||||
"horizon.options.lightbar.health": "سلامتی",
|
||||
"horizon.options.lightbar.dimension": "بعد",
|
||||
"horizon.options.glyphs.auto": "خودکار",
|
||||
"horizon.options.menu_focus": "تمرکز کنید",
|
||||
"horizon.options.menu_pointer": "اشاره گر",
|
||||
"horizon.options.keyboard.auto": "خودکار",
|
||||
"horizon.options.keyboard.steam": "بخار",
|
||||
"horizon.options.unavailable": "این ویژگی هنوز در Horizon موجود نیست.",
|
||||
|
||||
@@ -9,13 +9,10 @@
|
||||
"horizon.options.move_deadzone": "Liikkeen kuollut alue",
|
||||
"horizon.options.look_deadzone": "Katseen kuollut alue",
|
||||
"horizon.options.button_glyphs": "Painikkeiden kuviot",
|
||||
"horizon.options.menu_navigation": "Valikkonavigointi",
|
||||
"horizon.options.on_screen_keyboard": "Näyttönäppäimistö",
|
||||
"horizon.options.chat_delay": "Chatin viive",
|
||||
"horizon.options.lightbar.health": "Terveys",
|
||||
"horizon.options.lightbar.dimension": "Mitat",
|
||||
"horizon.options.menu_focus": "Keskity",
|
||||
"horizon.options.menu_pointer": "Osoitin",
|
||||
"horizon.options.unavailable": "Tämä ominaisuus ei ole vielä saatavilla Horizonissa.",
|
||||
"horizon.options.search": "Hakuasetukset...",
|
||||
"horizon.pages.mods": "Modit",
|
||||
|
||||
@@ -0,0 +1,429 @@
|
||||
{
|
||||
"horizon.options.vibration": "Panginginig ng boses",
|
||||
"horizon.options.adaptive_triggers": "Mga Adaptive Trigger",
|
||||
"horizon.options.look_sensitivity": "Sensitivity ng Tingin",
|
||||
"horizon.options.invert_x": "Baliktad na Tingin X",
|
||||
"horizon.options.invert_y": "Baliktad na Tingin Y",
|
||||
"horizon.options.sneak_button": "Pindutan ng Sneak",
|
||||
"horizon.options.move_deadzone": "Deadzone ng Paggalaw",
|
||||
"horizon.options.look_deadzone": "Deadzone ng Tingin",
|
||||
"horizon.options.button_glyphs": "Mga Glyph ng Button",
|
||||
"horizon.options.on_screen_keyboard": "On-Screen na Keyboard",
|
||||
"horizon.options.chat_delay": "Pagkaantala sa Chat",
|
||||
"horizon.options.lightbar.health": "Kalusugan",
|
||||
"horizon.options.lightbar.dimension": "Dimensyon",
|
||||
"horizon.options.unavailable": "Hindi pa available ang feature na ito sa Horizon.",
|
||||
"horizon.options.search": "Mga setting ng paghahanap...",
|
||||
"horizon.pages.mods": "Mga mod",
|
||||
"horizon.pages.shader_packs": "Mga Shader Pack",
|
||||
"horizon.pages.shader_options": "Mga Pagpipilian sa Shader",
|
||||
"horizon.pages.controller": "Mga Setting ng Controller",
|
||||
"horizon.pages.controller_binds": "Nagbubuklod ang Controller",
|
||||
"horizon.pages.extras": "Horizon Mga extra",
|
||||
"horizon.pages.settings": "Horizon Mga Setting",
|
||||
"horizon.pages.agent": "Ahente ng AI",
|
||||
"horizon.split.leave": "umalis",
|
||||
"horizon.pages.split_settings": "Mga Setting ng Splitscreen",
|
||||
"horizon.pages.split_profiles": "Sino naglalaro?",
|
||||
"horizon.pages.split_setup": "Pag-setup ng Splitscreen",
|
||||
"horizon.pages.music": "Musika",
|
||||
"horizon.pages.music.creative": "Malikhain",
|
||||
"horizon.pages.music.underwater": "Sa ilalim ng tubig",
|
||||
"horizon.pages.music.end": "Ang Katapusan",
|
||||
"horizon.pages.music.credits": "Mga kredito",
|
||||
"horizon.pages.music.end_biomes": "Tapusin ang mga biome",
|
||||
"horizon.pages.music.other": "Iba pang musika",
|
||||
"horizon.pages.music.empty": "Walang mga track ng musika: ang mga tunog ng laro ay hindi na-load.",
|
||||
"horizon.pages.music.tooltip": "Ang mga built-in na track, ayon sa sitwasyon: maglaro ng isa ngayon, o i-off ang anuman para ihinto ng laro ang pagpili nito.",
|
||||
"horizon.pages.settings.tooltip": "Sariling setting ni Horizon: graphics, controllers, extras at mods.",
|
||||
"horizon.pages.graphics.tooltip": "Mga graphic, simple: sinasabi ng bawat setting kung ano ang halaga nito.",
|
||||
"horizon.pages.graphics_advanced.tooltip": "Bawat graphics setting, kasama si Horizon, kung magkano ang halaga ng bawat isa.",
|
||||
"horizon.pages.controller.tooltip": "Mga Controller: ang kanilang mga button, stick, vibration at menu navigation.",
|
||||
"horizon.pages.extras.tooltip": "Mga opsyonal na karagdagan, lahat ay naka-off bilang default: ang laro ay mananatiling vanilla hanggang sa i-on mo ang isa.",
|
||||
"horizon.pages.agent.tooltip": "Hayaang maglaro ang sarili mong ahente ng AI: horizon-ctl at MCP client sa computer na ito.",
|
||||
"horizon.pages.split_profiles.tooltip": "Sino ang gumaganap: isang profile na nakatago sa folder ng larong ito.",
|
||||
"horizon.pages.split_setup.tooltip": "Ang mga bintana at monitor, at kung saan naglalaro.",
|
||||
"horizon.pages.shader_packs.tooltip": "Shader pack mula sa folder ng shaderpacks: sa sarili ni Horizon at sa mga shader/ format. Ang isa ay tumatakbo sa isang pagkakataon.",
|
||||
"horizon.pages.mods.tooltip": "Mga mod na ginawa para sa Horizon, mula sa folder ng horizon-mods. Ang bawat isa ay tumatakbo sa isang sandbox at nananatiling naka-off hanggang sa i-on mo ito.",
|
||||
"horizon.pages.open.graphics": "Mga graphic...",
|
||||
"horizon.pages.open.graphics_advanced": "Advanced na Graphics...",
|
||||
"horizon.pages.open.shader_packs": "Mga Shader Pack...",
|
||||
"horizon.pages.open.controller": "Mga Setting ng Controller...",
|
||||
"horizon.pages.open.extras": "Mga extra...",
|
||||
"horizon.pages.open.mods": "Mga mod...",
|
||||
"horizon.pages.open.agent": "Ahente ng AI...",
|
||||
"horizon.pages.open.horizon_graphics": "Horizon Mga graphic...",
|
||||
"horizon.pages.open.controller_binds": "Nagbubuklod ang Controller...",
|
||||
"horizon.pages.open.horizon_settings": "Horizon Mga Setting...",
|
||||
"horizon.pages.open.music": "Musika...",
|
||||
"horizon.mods.empty": "Walang mods: ilagay ang mga .hmod file sa horizon-mods folder",
|
||||
"horizon.mods.stopped": " (Tumigil)",
|
||||
"horizon.mods.not_built": " (Hindi binuo)",
|
||||
"horizon.mods.settings": "Mga setting",
|
||||
"horizon.mods.in_world": " (iwanan ang mundo upang magbago)",
|
||||
"horizon.mods.open_folder": "Buksan ang Mod Folder",
|
||||
"horizon.shader_packs.empty": "Walang shader pack: ilagay ang mga ito sa shaderpacks folder",
|
||||
"horizon.shader_options.open": "Mga Pagpipilian sa Shader...",
|
||||
"horizon.shader_options.loading": "Binabasa ang mga opsyon ng shader pack...",
|
||||
"horizon.agent.copy_details": "Kopyahin ang Mga Detalye ng Koneksyon",
|
||||
"horizon.multiplayer.join": "Sumali",
|
||||
"horizon.multiplayer.cancel_reconnecting": "Kanselahin ang Muling Pagkonekta",
|
||||
"horizon.multiplayer.join_friend": "Sumali sa isang Kaibigan",
|
||||
"horizon.multiplayer.invite_code": "Code ng Imbitasyon",
|
||||
"horizon.multiplayer.relay": "Relay (opsyonal)",
|
||||
"LOD Distance": "LOD Distansya",
|
||||
"Far Detail": "Malayong Detalye",
|
||||
"Chunk Updates": "Mga Update ng Tipak",
|
||||
"Upload Budget": "Mag-upload ng Badyet",
|
||||
"Fog": "Ulap",
|
||||
"Weather": "Panahon",
|
||||
"Animated Textures": "Mga Animated na Texture",
|
||||
"Present Mode": "Kasalukuyang Mode",
|
||||
"Worker Threads": "Mga Thread ng Manggagawa",
|
||||
"Resolution Scale": "Iskala ng Resolusyon",
|
||||
"Paper White": "Papel na Puti",
|
||||
"Peak Brightness": "Tuktok na Liwanag",
|
||||
"Black Level": "Itim na Antas",
|
||||
"UI Brightness": "Liwanag ng UI",
|
||||
"Battery Mode": "Mode ng Baterya",
|
||||
"Performance Overlay": "Overlay ng Pagganap",
|
||||
"Full Detail Distance": "Buong Detalye ng Distansya",
|
||||
"On": "Naka-on",
|
||||
"Off": "Naka-off",
|
||||
"Unlimited": "Walang limitasyon",
|
||||
"Performance": "Pagganap",
|
||||
"Balanced": "Balanseng",
|
||||
"Quality": "Kalidad",
|
||||
"Native": "Orihinal",
|
||||
"Full": "Puno",
|
||||
"Reduced": "Nabawasan",
|
||||
"Efficient": "Mahusay",
|
||||
"Precise": "tumpak",
|
||||
"Immediate": "Agad-agad",
|
||||
"FPS and Graph": "FPS at Graph",
|
||||
"No cost": "Walang gastos",
|
||||
"Low cost": "Mababang gastos",
|
||||
"Medium cost": "Katamtamang halaga",
|
||||
"High cost": "Mataas na gastos",
|
||||
"Saves time": "Nakakatipid ng oras",
|
||||
"Graphics": "Mga graphic",
|
||||
"Done": "Tapos na",
|
||||
"This feature is not yet available in Horizon.": "Hindi pa available ang feature na ito sa Horizon.",
|
||||
"Your display or system doesn't offer HDR output.": "Ang iyong display o system ay hindi nag-aalok ng HDR output.",
|
||||
"Turn HDR on to use it.": "I-on ang HDR para magamit ito.",
|
||||
"Your GPU or graphics API doesn't support it.": "Hindi ito sinusuportahan ng iyong GPU o graphics API.",
|
||||
"%s chunks": "%s tipak",
|
||||
"%s per frame": "%s bawat frame",
|
||||
"Full-detail terrain range. LOD Distance can extend local worlds farther.": "Saklaw ng buong detalye ng lupain. Maaaring pahabain ng LOD Distance ang mga lokal na mundo nang mas malayo.",
|
||||
"Coarse distant terrain in local worlds. Integrated GPUs stop at 128 chunks.": "Magaspang na malayong lupain sa mga lokal na mundo. Humihinto ang mga pinagsamang GPU sa 128 chunks.",
|
||||
"Reduced draws far terrain coarser: faster on this integrated GPU.": "Ang pinababang kumukuha ng malayong lupain ay mas magaspang: mas mabilis sa pinagsamang GPU na ito.",
|
||||
"Reduced draws far terrain coarser, for GPUs it slows down.": "Ang pinababang kumukuha ng malayong lupain ay mas magaspang, para sa mga GPU ay bumagal ito.",
|
||||
"Field of view. Wider shows more terrain at once.": "Larangan ng pananaw. Ang mas malawak ay nagpapakita ng mas maraming lupain nang sabay-sabay.",
|
||||
"Caps frames per second; a cap saves power and heat.": "I-cap ang mga frame sa bawat segundo; ang takip ay nakakatipid ng kuryente at init.",
|
||||
"Waits for the display's refresh: no tearing, a little latency.": "Naghihintay para sa pag-refresh ng display: walang punit, kaunting latency.",
|
||||
"Size of menus and the HUD.": "Sukat ng mga menu at ang HUD.",
|
||||
"Sets the options below together. Changing one makes it Custom.": "Pinagsasama-sama ang mga opsyon sa ibaba. Ang pagpapalit ng isa ay ginagawa itong Custom.",
|
||||
"Lava, fire and sunlight shine brighter than white. Needs an HDR display.": "Lava, apoy at sikat ng araw ay mas maliwanag kaysa puti. Kailangan ng HDR display.",
|
||||
"Your display's darkest black. 0 for OLED; LCDs glow a little.": "Pinakamadilim na itim ang iyong display. 0 para sa OLED; Medyo kumikinang ang mga LCD.",
|
||||
"How bright highlights get. Auto: the peak your system reports.": "Kung gaano kaliwanag ang mga highlight. Auto: ang pinakamataas na ulat ng iyong system.",
|
||||
"How bright white paper and menus look. Auto: your desktop's white.": "Gaano kaliwanag ang puting papel at mga menu. Auto: puti ng iyong desktop.",
|
||||
"How bright the HUD and menus are, against paper white.": "Gaano kaliwanag ang HUD at mga menu, laban sa puting papel.",
|
||||
"How far mobs, crops and machines keep working. CPU time.": "Hanggang saan patuloy na gumagana ang mga mandurumog, pananim at makina. oras ng CPU.",
|
||||
"How far away mobs and items are drawn, as a share of normal.": "Kung gaano kalayo ang mga mandurumog at mga item ay iginuhit, bilang bahagi ng normal.",
|
||||
"Skips terrain hidden behind closed sections. Off costs a lot.": "Nilalaktawan ang lupain na nakatago sa likod ng mga saradong seksyon. Malaki ang gastos sa off.",
|
||||
"Hides entities behind opaque blocks.": "Itinatago ang mga entity sa likod ng mga opaque na bloke.",
|
||||
"No entity occlusion culling.": "Walang entity occlusion culling.",
|
||||
"CPU occlusion test runs this frame.": "Pinapatakbo ng CPU occlusion test ang frame na ito.",
|
||||
"Occlusion checks run on a worker thread.": "Ang mga pagsusuri sa occlusion ay tumatakbo sa isang thread ng manggagawa.",
|
||||
"Meshed sections uploaded per frame. Lower is smoother while loading.": "Mga naka-meshed na seksyon na na-upload bawat frame. Ang ibaba ay mas makinis habang naglo-load.",
|
||||
"Soft shadows in corners. Costs chunk building time only.": "Malambot na mga anino sa mga sulok. Gastos ng chunk building time lang.",
|
||||
"Smaller copies of block textures for distant terrain: less shimmer.": "Mas maliliit na kopya ng mga block texture para sa malayong lupain: mas kaunting shimmer.",
|
||||
"Blends grass and water colours across biomes when building chunks.": "Pinagsasama ang mga kulay ng damo at tubig sa mga biome kapag gumagawa ng mga tipak.",
|
||||
"Cloud layer: off, flat (fast) or 3D (fancy).": "Cloud layer: naka-off, flat (mabilis) o 3D (fancy).",
|
||||
"How far clouds reach, in chunks.": "Gaano kalayo ang naabot ng mga ulap, sa mga tipak.",
|
||||
"Draws the sky, sun, moon and stars.": "Iginuhit ang langit, araw, buwan at mga bituin.",
|
||||
"Distance fog. Off shows the edge of the loaded world.": "Distance fog. Ipinapakita ng Off ang gilid ng na-load na mundo.",
|
||||
"Draws rain and snow.": "Gumuguhit ng ulan at niyebe.",
|
||||
"How far rain and snow fall around you.": "Gaano kalayo ang ulan at niyebe sa paligid mo.",
|
||||
"How many particles effects spawn.": "Gaano karaming mga particle ang mga epekto ng mga itlog.",
|
||||
"Round shadows under mobs and items.": "Mga bilog na anino sa ilalim ng mga mob at item.",
|
||||
"Leaves with see-through gaps. Off draws them solid.": "Mga dahon na may nakikitang mga puwang. Off draws ang mga ito solid.",
|
||||
"Sorts water and glass more exactly behind each other.": "Pinag-uuri-uriin ang tubig at baso nang mas eksakto sa likod ng bawat isa.",
|
||||
"Which chunk rebuilds wait for the frame: none, nearby or yours.": "Aling chunk ang muling itatayo ang naghihintay para sa frame: wala, malapit o sa iyo.",
|
||||
"Animates water, lava, fire and other moving textures.": "Binibigyang-buhay ang tubig, lava, apoy at iba pang gumagalaw na texture.",
|
||||
"World pixels per screen pixel. Below 100% is faster on the GPU.": "World pixels bawat screen pixel. Ang mas mababa sa 100% ay mas mabilis sa GPU.",
|
||||
"Smooths jagged edges. FXAA: softer. TAA: smoothest, moving things may trail.": "Makinis ang tulis-tulis na mga gilid. FXAA: mas malambot. TAA: Ang pinakamakinis, gumagalaw na mga bagay ay maaaring masunod.",
|
||||
"Renders the world smaller and rebuilds it with TAA. Faster, softer.": "Ginagawang mas maliit ang mundo at muling itinatayo ito gamit ang TAA. Mas mabilis, mas malambot.",
|
||||
"HDR output on an HDR display: lava, fire and sunlight shine brighter.": "HDR na output sa isang HDR display: lava, apoy at sikat ng araw ay kumikinang nang mas maliwanag.",
|
||||
"How frames reach the screen while VSync is off.": "Paano naaabot ng mga frame ang screen habang naka-off ang VSync.",
|
||||
"Efficient sleeps until the next frame; Precise spins, like vanilla.": "Mahusay na pagtulog hanggang sa susunod na frame; Mga tumpak na pag-ikot, tulad ng vanilla.",
|
||||
"Fills the screen (borderless).": "Pinuno ang screen (walang hangganan).",
|
||||
"Brightens dark places.": "Nagpapaliwanag ng mga madilim na lugar.",
|
||||
"Lowers the frame rate when minimised, or idle too.": "Ibinababa ang frame rate kapag pinaliit, o idle din.",
|
||||
"Sways the view while walking.": "Iniindayog ang tanawin habang naglalakad.",
|
||||
"Fades newly loaded chunks in.": "Nagfades ang mga bagong na-load na chunks.",
|
||||
"Darkens the screen's edges.": "Pinadidilim ang mga gilid ng screen.",
|
||||
"Shows when the world saves.": "Ipinapakita kung kailan nagliligtas ang mundo.",
|
||||
"Shows attack cooldown.": "Nagpapakita ng cooldown ng pag-atake.",
|
||||
"60 FPS cap (30 in menus or unfocused), half the workers: less power.": "60 FPS cap (30 sa mga menu o hindi nakatutok), kalahati ng mga manggagawa: mas kaunting lakas.",
|
||||
"Threads that generate, light and mesh chunks. Next start.": "Mga thread na bumubuo, magaan, at mga tipak ng mata. Susunod na simula.",
|
||||
"Vulkan, then DirectX 12 (Windows) or OpenGL (Linux) where it fails. Next start.": "Vulkan, pagkatapos ay DirectX 12 (Windows) o OpenGL (Linux) kung saan ito nabigo. Susunod na simula.",
|
||||
"Water and glass in one buffer: fewer draw calls, a bit more VRAM. Next start.": "Tubig at baso sa isang buffer: mas kaunting mga draw call, medyo mas VRAM. Susunod na simula.",
|
||||
"Mesh data sent to the GPU per frame. Lower is smoother while loading.": "Mesh data na ipinadala sa GPU bawat frame. Ang ibaba ay mas makinis habang naglo-load.",
|
||||
"Frame rate and frame times over the game, with a graph.": "Frame rate at frame times sa laro, na may graph.",
|
||||
"horizon.multiplayer.finding_friend": "Hinahanap ang mundo ng iyong kaibigan...",
|
||||
"horizon.multiplayer.not_signed_in": "Nasa online mode ang server na ito. Mag-sign in gamit ang iyong Microsoft account sa Horizon launcher para sumali dito.",
|
||||
"horizon.multiplayer.invalid_address": "Di-wastong address ng server: %s",
|
||||
"horizon.multiplayer.connected_friend_direct": "Direktang konektado sa iyong kaibigan...",
|
||||
"horizon.multiplayer.connected_friend_relay": "Nakakonekta sa iyong kaibigan sa pamamagitan ng relay...",
|
||||
"General": "Heneral",
|
||||
"Undo": "I-undo",
|
||||
"Search options": "Mga opsyon sa paghahanap",
|
||||
"Distance": "Distansya",
|
||||
"Display": "Pagpapakita",
|
||||
"Sky and weather": "Langit at panahon",
|
||||
"Lighting and entities": "Pag-iilaw at mga nilalang",
|
||||
"Textures": "Mga texture",
|
||||
"Image": "Imahe",
|
||||
"Chunk loading": "Naglo-load ng tipak",
|
||||
"Power": "kapangyarihan",
|
||||
"Frames": "Mga frame",
|
||||
"Brightness": "Liwanag",
|
||||
"How far you see, the window and the HUD.": "Kung gaano kalayo ang nakikita mo, ang bintana at ang HUD.",
|
||||
"The sky and weather, lighting, textures and the image.": "Ang langit at panahon, pag-iilaw, mga texture at ang imahe.",
|
||||
"Chunk loading, culling and power use.": "Chunk loading, culling at paggamit ng kuryente.",
|
||||
"How frames reach the screen, and the performance overlay.": "Paano naaabot ng mga frame ang screen, at ang overlay ng performance.",
|
||||
"Brighter-than-white output on an HDR display.": "Mas maliwanag kaysa sa puting output sa isang HDR display.",
|
||||
"Results for \"%s\"": "Mga resulta para sa \"%s\"",
|
||||
"No settings match.": "Walang tumutugma sa mga setting.",
|
||||
"horizon.title.not_affiliated": "Hindi kaakibat sa Mojang o Microsoft",
|
||||
"horizon.extras.header.lighting": "Pag-iilaw",
|
||||
"horizon.extras.header.third_person": "Pangatlong tao",
|
||||
"horizon.extras.header.particles": "Mga particle",
|
||||
"horizon.extras.header.inventory": "Imbentaryo",
|
||||
"horizon.extras.header.sound": "Tunog",
|
||||
"horizon.extras.header.menus": "Mga menu",
|
||||
"horizon.extras.dynamic_lights": "Mga dynamic na ilaw",
|
||||
"horizon.extras.own_name_tag": "Sariling name tag",
|
||||
"horizon.extras.hide_block_particles": "Itago ang mga block-break na particle",
|
||||
"horizon.extras.auto_reconnect": "Awtomatikong kumonekta muli",
|
||||
"horizon.extras.ui_sound_reserve": "Panatilihin ang mga channel para sa mga tunog ng UI",
|
||||
"horizon.extras.music_page": "Pahina ng musika",
|
||||
"horizon.extras.mouse_tweaks": "Mga kontrol ng Mouse Tweaks",
|
||||
"horizon.extras.mouse_tweaks_wheel": "Gumagalaw ang scroll wheel ng mga item",
|
||||
"horizon.extras.sort": "Mga pindutan ng pag-uri-uriin",
|
||||
"horizon.extras.no_ai": "Walang AI",
|
||||
"horizon.extras.agent_control": "Kontrol ng Ahente",
|
||||
"horizon.extras.chat_animation": "Makinis na chat",
|
||||
"horizon.extras.chat_indicator": "Tagapagpahiwatig ng mensahe",
|
||||
"horizon.extras.wheel_cycles_settings": "Nagbabago ang mga setting ng scroll wheel",
|
||||
"horizon.extras.fullbright.tooltip": "Ipakita ang mga bloke at entity sa ganap na liwanag, kahit na sa madilim na lugar.",
|
||||
"horizon.extras.dynamic_lights.tooltip": "Ang mga sulo at iba pang pinagmumulan ng liwanag na hawak, nalaglag o nasusunog ay nagpapasindi sa mga bloke sa paligid nila.",
|
||||
"horizon.extras.own_name_tag.tooltip": "Ipinapakita ang iyong pangalan sa itaas ng iyong ulo sa pangatlong tao, tulad ng nakikita ng ibang mga manlalaro. Nakatago kapag itinago ng server ang mga pangalan ng iyong team o hindi ka nakikita.",
|
||||
"horizon.extras.hide_block_particles.tooltip": "Itinatago ang mga debris na particle na sumabog mula sa isang sirang bloke at gumuho sa iyong minahan. Ang iba pang mga particle ay nananatili.",
|
||||
"horizon.extras.auto_reconnect.tooltip": "Sumali muli sa isang server pagkatapos ng isang nawalang koneksyon o isang pag-restart, hindi kailanman pagkatapos ng isang sipa o pagbabawal.",
|
||||
"horizon.extras.ui_sound_reserve.tooltip": "Ang mga tunog sa mundo ay nag-iiwan ng 16 sa 247 na sound channel na libre, kaya ang baha sa kanila (isang malaking pagsabog) ay hindi maaaring patahimikin ang mga pag-click sa menu.",
|
||||
"horizon.extras.music_page.tooltip": "Ang Music & Sounds ay nakakakuha ng Music... page: i-play ang anumang built-in na track ngayon, o i-off ang isa para tumigil ang laro sa pagpili nito. Walang magbabago hanggang sa i-off mo ang isang track.",
|
||||
"horizon.extras.mouse_tweaks.tooltip": "Ang right-drag ay naglalagay ng isa sa bawat slot, ang left-drag ay kumukuha ng hawak na item, Shift + left-drag ang gumagalaw sa bawat slot.",
|
||||
"horizon.extras.mouse_tweaks_wheel.tooltip": "Ang Down ay nagpapadala ng isang item ng slot sa kabilang panig, ang pataas ay nagbabalik ng isa.",
|
||||
"horizon.extras.sort.tooltip": "Pinag-uuri-uri ang imbentaryo, mga chest, barrel, ender chest at shulker box sa malikhaing pagkakasunud-sunod ng tab, pinagsasama-sama ang mga stack.",
|
||||
"horizon.extras.sort_key.tooltip": "Pinagbukud-bukod ang bahagi sa ilalim ng cursor. Mag-click, pagkatapos ay pindutin ang isang key; Tinatanggal ito ng pagtakas.",
|
||||
"horizon.extras.no_ai.tooltip": "Itinatago at ino-off ang bawat feature ng AI: control ng ahente, horizon-ctl at ang mga MCP server. Ang switch din ng launcher.",
|
||||
"horizon.extras.agent_control.tooltip": "Ang iyong sariling ahente ng AI ay maaaring laruin ang larong ito sa pamamagitan ng horizon-ctl o isang MCP client, sa computer na ito lamang.",
|
||||
"horizon.extras.discord_presence.tooltip": "Ipinapakita ang Paglalaro ng Horizon sa iyong Discord profile habang tumatakbo ang Discord: mga menu, single player o multiplayer, ang dimensyon at ang oras ng paglalaro. Hindi kailanman pangalan ng mundo o address ng server.",
|
||||
"Calibrate...": "I-calibrate...",
|
||||
"Calibrate Anyway...": "Mag-calibrate pa rin...",
|
||||
"Use Automatic Setup": "Gamitin ang Awtomatikong Pag-setup",
|
||||
"Next": "Susunod",
|
||||
"HDR Calibration %s/%s: %s": "Pag-calibrate ng HDR %s/%s: %s",
|
||||
"Sets the three below full screen, one test picture at a time.": "Itinatakda ang tatlo sa ibaba ng full screen, isang pagsubok na larawan sa isang pagkakataon.",
|
||||
"A key that opens this screen from the game. Not bound at first.": "Isang susi na nagbubukas ng screen na ito mula sa laro. Hindi nakatali sa una.",
|
||||
"Your display didn't say how bright it gets: calibrate to set it up.": "Hindi sinabi ng iyong display kung gaano ito kaliwanag: i-calibrate para i-set up ito.",
|
||||
"Already set up for your display. Only calibrate if HDR looks wrong.": "Naka-set up na para sa iyong display. I-calibrate lang kung mukhang mali ang HDR.",
|
||||
"Puts Peak Brightness and Paper White back to your display's setup.": "Ibinabalik ang Peak Brightness at Paper White sa setup ng iyong display.",
|
||||
"Set up for your display. Leave on Auto unless it looks wrong.": "I-set up para sa iyong display. Umalis sa Auto maliban kung mukhang mali.",
|
||||
"Lower it until the logo just disappears into the black.": "Ibaba ito hanggang sa mawala na lang sa itim ang logo.",
|
||||
"Raise it until the logo just disappears into the bright square.": "Itaas ito hanggang sa mawala na lang ang logo sa maliwanag na parisukat.",
|
||||
"Make the card a white that's comfortable to look at for a long time, in the light you play in.": "Gawing puti ang card na kumportableng tingnan sa mahabang panahon, sa liwanag na iyong nilalaro.",
|
||||
"horizon.splitscreen.profiles.forget": "Kalimutan",
|
||||
"horizon.splitscreen.profiles.create": "Lumikha",
|
||||
"horizon.splitscreen.profiles.you": " - ikaw",
|
||||
"horizon.splitscreen.profiles.forget_named": "Kalimutan %s",
|
||||
"horizon.splitscreen.profiles.previous": "Nakaraang",
|
||||
"horizon.splitscreen.profiles.next": "Susunod",
|
||||
"horizon.splitscreen.profiles.new_button": "Bagong Profile...",
|
||||
"horizon.splitscreen.profiles.forget_title": "Kalimutan ang profile?",
|
||||
"horizon.splitscreen.profiles.forget_leaves": "Umalis ito sa listahan ng pagkakataong ito.",
|
||||
"horizon.splitscreen.profiles.forget_kept": "Ang pag-unlad ng mundo at mga setting ay pinapanatili.",
|
||||
"horizon.splitscreen.profiles.new_title": "Bagong Profile",
|
||||
"horizon.splitscreen.profiles.name_hint": "Pangalan (3 hanggang 16 na letra, digit, _)",
|
||||
"horizon.splitscreen.profiles.switch_title": "Lumipat ng profile",
|
||||
"horizon.splitscreen.profiles.offline_note": "Ang mga offline na profile ay kabilang sa pagkakataong ito",
|
||||
"horizon.splitscreen.profiles.move": "Lumipat kung saan ka naglalaro",
|
||||
"horizon.splitscreen.profiles.move_place": "Ilipat kung saan ka naglalaro: %s",
|
||||
"horizon.friends.title": "Makipaglaro sa Kaibigan",
|
||||
"horizon.friends.hint": "I-paste ng mga kaibigan ang code pagkatapos ng button na Friends ng screen ng pamagat, sa Direktang Koneksyon, o sa Play page ng launcher.",
|
||||
"horizon.friends.copied": "Kinopya",
|
||||
"horizon.friends.copy_code": "Kopyahin ang Code",
|
||||
"horizon.friends.stop_sharing": "Itigil ang Pagbabahagi",
|
||||
"horizon.friends.none_yet": "Wala pang kaibigan dito.",
|
||||
"horizon.friends.here_now": "Narito ngayon: %s",
|
||||
"horizon.friends.share_intro": "Ibahagi ang mundong ito sa likod ng code ng imbitasyon: bumubukas ito sa LAN, at sumali ang mga kaibigan sa internet gamit ang code. Walang kasamang server namin.",
|
||||
"horizon.friends.start_sharing": "Simulan ang Pagbabahagi",
|
||||
"horizon.friends.troubleshooting": "Pag-troubleshoot...",
|
||||
"horizon.friends.stopped": "Huminto sa pagbabahagi ng code ng imbitasyon.",
|
||||
"horizon.friends.short_code_changed": "May sumubok ng maling maikling code, kaya nagbago ito.",
|
||||
"horizon.friends.wrong_code": "May sumubok ng maling code.",
|
||||
"horizon.friends.code_ready": "Handa na ang iyong code ng imbitasyon: Game Menu, Play with Friends. Kopyahin ito at ipadala sa iyong mga kaibigan.",
|
||||
"horizon.friends.share_failed": "Hindi maibahagi ang mundo: %s",
|
||||
"horizon.friends.finding_route": "Hinahanap kung paano ka maaabot ng mga kaibigan...",
|
||||
"horizon.osk.shift": "Paglipat",
|
||||
"horizon.osk.space": "kalawakan",
|
||||
"horizon.osk.delete": "Tanggalin",
|
||||
"horizon.osk.type": "Uri",
|
||||
"horizon.osk.symbols": "Mga simbolo",
|
||||
"horizon.osk.close": "Isara",
|
||||
"horizon.extras.chat_animation.tooltip": "Ang isang bagong linya ng chat ay dumudulas mula sa kaliwa habang ito ay nawawala, sa halip na lumabas nang buo.",
|
||||
"horizon.extras.chat_indicator.tooltip": "Ang may kulay na bar sa kaliwa ng isang chat line.",
|
||||
"horizon.extras.wheel_cycles_settings.tooltip": "Ang scroll wheel sa ibabaw ng isang button sa mga setting ay nagbabago ng halaga nito, tulad ng sa vanilla. Naka-off, ini-scroll lang ng gulong ang listahan.",
|
||||
"horizon.extras.pack_browser.tooltip": "Ang Select Resource Packs ay nakakakuha ng Add button na naghahanap sa Modrinth at nag-i-install ng pack sa iyong pack folder. Wala, ang laro ay hindi kailanman nakikipag-ugnayan sa Modrinth.",
|
||||
"horizon.extras.splitscreen.tooltip": "Sa isang mundo, maaaring sumali ang isa pang controller bilang bagong player: pindutin ang A kapag nagtanong ito, pagkatapos ay pumili ng profile at kung saan maglaro.",
|
||||
"horizon.splitscreen.setup.monitor": "Subaybayan %s",
|
||||
"horizon.splitscreen.setup.monitor_unknown": "isang monitor",
|
||||
"horizon.splitscreen.setup.window": "Bintana %s",
|
||||
"horizon.splitscreen.setup.new_window": "Bagong window",
|
||||
"horizon.splitscreen.setup.fill_monitor": "Punan ang %s",
|
||||
"horizon.splitscreen.setup.done": "Tapos na",
|
||||
"horizon.splitscreen.setup.on": "Naka-on",
|
||||
"horizon.splitscreen.setup.off": "Naka-off",
|
||||
"horizon.splitscreen.setup.player": "Manlalaro %s",
|
||||
"horizon.splitscreen.setup.revert": "Ibalik",
|
||||
"horizon.splitscreen.setup.apply": "Mag-apply",
|
||||
"horizon.splitscreen.setup.warning.empty_main": "Walang naglalaro sa Window 1: nagtatago ito",
|
||||
"horizon.splitscreen.setup.warning.empty_close": "Walang naglalaro sa Window %s: nagsasara ito sa Ilapat",
|
||||
"horizon.splitscreen.setup.warning.empty_new": "Walang naglalaro sa Window %s: hindi ito magbubukas",
|
||||
"horizon.splitscreen.setup.warning.on_main": "Pinuno ng Window %s ang monitor ng Window 1: naglalaro ang mga manlalaro nito sa Window 1",
|
||||
"horizon.splitscreen.setup.warning.unplugged": "Ang monitor ng Window %s ay hindi konektado: ang mga manlalaro nito ay naglalaro sa Window 1",
|
||||
"horizon.splitscreen.setup.status.off": "Naka-off ang splitscreen.",
|
||||
"horizon.splitscreen.setup.status.enable_hint": "I-on ito, pagkatapos ay pindutin ang isang button sa isa pang controller sa isang mundo.",
|
||||
"horizon.splitscreen.setup.status.join_hint": "Pindutin ang A para sumali at pumili ng profile.",
|
||||
"horizon.splitscreen.setup.status.alone": "Walang ibang mga lokal na manlalaro.",
|
||||
"horizon.splitscreen.setup.status.solo_controls": "Ang mga solong kontrol at feedback ng controller ay hindi nagbabago.",
|
||||
"horizon.splitscreen.setup.window_empty": "Window %s: walang laman",
|
||||
"horizon.splitscreen.setup.note.select": "Mag-click sa isang player, o i-drag ito sa isang window o isang monitor.",
|
||||
"horizon.splitscreen.setup.note.apply": "Mag-apply upang maglaro sa ganitong paraan, Bumalik sa pag-undo.",
|
||||
"horizon.splitscreen.setup.note.place": "Saan dapat maglaro si %s?",
|
||||
"horizon.splitscreen.setup.this_player": "ang manlalarong ito",
|
||||
"horizon.splitscreen.setup.switch_disabled": "Nag-o-off ang Splitscreen kapag umalis na ang iba (ang kanilang menu sa pag-pause).",
|
||||
"horizon.splitscreen.setup.window_place": "Window %s (%s ng %s)",
|
||||
"horizon.splitscreen.setup.names": "Mga pangalan",
|
||||
"horizon.splitscreen.setup.identify": "Kilalanin",
|
||||
"horizon.splitscreen.setup.layout.two": "2 pagbabahagi: %s",
|
||||
"horizon.splitscreen.setup.layout.three": "3 pagbabahagi: %s",
|
||||
"horizon.splitscreen.setup.layout.two.1": "Magkatabi",
|
||||
"horizon.splitscreen.setup.layout.two.2": "Itaas at ibaba",
|
||||
"horizon.splitscreen.setup.layout.three.0": "Isang malawak sa itaas",
|
||||
"horizon.splitscreen.setup.layout.three.1": "Isang matangkad sa kaliwa",
|
||||
"horizon.splitscreen.setup.layout.three.2": "Magkatabi",
|
||||
"horizon.splitscreen.setup.help.player": "I-click o i-drag ang %s upang ilipat ang mga ito.",
|
||||
"horizon.splitscreen.setup.help.layout_auto": "%s (magkatabi kapag malapad ang bintana). Pindutin upang baguhin.",
|
||||
"horizon.splitscreen.setup.help.layout": "%s. Pindutin upang baguhin.",
|
||||
"horizon.splitscreen.setup.help.switch": "Splitscreen para sa computer na ito, naka-on o naka-off.",
|
||||
"horizon.splitscreen.setup.help.identify": "Ipinapakita ng view ng bawat manlalaro kung saang window ito naroroon.",
|
||||
"horizon.splitscreen.setup.help.names": "Ang pangalan ng bawat manlalaro sa sulok ng kanilang view.",
|
||||
"horizon.splitscreen.setup.help.revert": "I-undo ang mga pagbabagong hindi pa nalalapat.",
|
||||
"horizon.splitscreen.setup.help.apply": "I-play ang paraang ipinapakita ng mapa.",
|
||||
"horizon.splitscreen.setup.help.unchanged": "Wala pa ring pinagbago.",
|
||||
"horizon.splitscreen.setup.give_up_pad": "Isuko Pad",
|
||||
"horizon.splitscreen.prompt.controller_connected": "Nakakonekta ang controller",
|
||||
"horizon.splitscreen.prompt.controller_disconnected": "Nadiskonekta ang controller",
|
||||
"horizon.splitscreen.prompt.controller_disconnected.hint": "Ikonekta itong muli, o pindutin ang isang pindutan sa isa pa",
|
||||
"horizon.splitscreen.prompt.join.one": "Gustong sumali ni %s",
|
||||
"horizon.splitscreen.prompt.join.many": "Gustong sumali ng %s controllers",
|
||||
"horizon.splitscreen.prompt.join.yes": "Sumali",
|
||||
"horizon.splitscreen.prompt.join.as_p1": "Maglaro bilang P1",
|
||||
"horizon.splitscreen.prompt.join.no": "Hindi",
|
||||
"horizon.splitscreen.prompt.lost": "%s: nadiskonekta ang controller",
|
||||
"horizon.splitscreen.prompt.lost.use_another": "Gumamit ng iba",
|
||||
"horizon.splitscreen.prompt.lost.leave": "umalis",
|
||||
"horizon.splitscreen.setup.help.give_up_pad": "Ang iyong controller ay huminto sa pagmamaneho sa iyo at inaalok na sumali (A).",
|
||||
"horizon.splitscreen.setup.note.held_at": "%s hanggang %s: Ibinaba ni A dito, ibinalik ni B.",
|
||||
"horizon.splitscreen.setup.note.held": "%s pinulot: kaliwa/kanan pumili kung saan, ibinabagsak ni A, ibinabalik ito ni B.",
|
||||
"Hides models behind opaque blocks. Async checks off-thread; entities tick.": "Itinatago ang mga modelo sa likod ng mga opaque na bloke. Sinusuri ng Async ang off-thread; lagyan ng tsek ang mga entidad.",
|
||||
"Block Entities": "I-block ang mga Entity",
|
||||
"Shulker Boxes": "Mga Kahon ng Shulker",
|
||||
"Reuses settled boxes; lid movement stays animated.": "Muling ginagamit ang mga nakaayos na kahon; nananatiling animated ang paggalaw ng talukap ng mata.",
|
||||
"Signs": "Mga palatandaan",
|
||||
"Reuses sign text until text, light, or font changes.": "Muling ginagamit ang sign text hanggang sa magbago ang text, ilaw, o font.",
|
||||
"Decorated Pots": "Pinalamutian na mga kaldero",
|
||||
"Reuses still pots; break wobble and sherd changes redraw.": "Gumamit muli ng mga kaldero; break wobble at sherd pagbabago redraw.",
|
||||
"Bells": "Mga kampana",
|
||||
"Reuses still bells; ringing stays animated.": "Gumamit muli ng mga kampana; nananatiling animated ang tugtog.",
|
||||
"Chests": "Mga dibdib",
|
||||
"Reuses closed chests; moving lids stay animated.": "Muling ginagamit ang mga saradong dibdib; nananatiling animated ang mga gumagalaw na takip.",
|
||||
"Banners": "Mga banner",
|
||||
"Reuses poles; flags and pattern layers still update.": "Gumamit muli ng mga poste; nag-a-update pa rin ang mga flag at pattern layer.",
|
||||
"Copper Golem Statues": "Mga Estatwa ng Copper Golem",
|
||||
"Reuses statue geometry until its block state changes.": "Gumamit muli ng geometry ng estatwa hanggang sa magbago ang block state nito.",
|
||||
"Leaf Culling": "Paghukay ng dahon",
|
||||
"Every leaf face. Vanilla's fancy leaves.": "Bawat dahon mukha. Magarbong dahon ng vanilla.",
|
||||
"Distant Plant Dither": "Malayong Plant Dither",
|
||||
"Keeps fine plants in high-res packs from fading far away.": "Pinapanatili ang magagandang halaman sa mga high-res na pack na hindi kumukupas sa malayo.",
|
||||
"Screenshot Quality": "Kalidad ng Screenshot",
|
||||
"F2 screenshots at this many times the game's resolution. Higher takes longer.": "Ang mga screenshot ng F2 sa ito ay maraming beses sa resolution ng laro. Mas tumatagal ang mas mataas.",
|
||||
"Frame Generation": "Pagbuo ng Frame",
|
||||
"Shows a made-up frame between each two real ones: smoother, a little more lag.": "Nagpapakita ng ginawang frame sa pagitan ng bawat dalawang tunay: mas makinis, mas lag.",
|
||||
"Reuses the pack shadow map when sun, view and world match. Off by default.": "Muling ginagamit ang pack shadow map kapag nagtugma ang araw, view at mundo. Naka-off bilang default.",
|
||||
"Find BlueMap": "Hanapin ang BlueMap",
|
||||
"On servers, finds their BlueMap web map for far terrain. Next join.": "Sa mga server, hinahanap ang kanilang BlueMap web map para sa malayong lupain. Susunod na sumali.",
|
||||
"How far around you BlueMap tiles are downloaded. Next join.": "Gaano kalayo sa paligid mo ang mga tile ng BlueMap ay na-download. Susunod na sumali.",
|
||||
"Synchronous": "Kasabay",
|
||||
"Hollow": "guwang",
|
||||
"Leaves fully inside a canopy draw solid: fewer see-through layers.": "Ang mga dahon na ganap sa loob ng canopy ay gumuhit ng solid: mas kaunting mga see-through na layer.",
|
||||
"Leaves with one open side draw solid too: faster, chunkier edges.": "Ang mga dahon na may isang bukas na gilid ay gumuhit din ng solid: mas mabilis, mas makapal na mga gilid.",
|
||||
"Drops faces between leaves: faster, but gaps look through.": "Ibinababa ang mga mukha sa pagitan ng mga dahon: mas mabilis, ngunit ang mga puwang ay lumilipas.",
|
||||
"Hotbar: Previous Slot": "Hotbar: Nakaraang Slot",
|
||||
"Hotbar: Next Slot": "Hotbar: Susunod na Slot",
|
||||
"horizon.agent.connected.one": "Konektado: 1 koneksyon ng ahente",
|
||||
"horizon.agent.connected.many": "Konektado: %s na koneksyon ng ahente",
|
||||
"horizon.agent.connected.one_ago": "Konektado: 1 koneksyon ng ahente, huling utos %s s ang nakalipas",
|
||||
"horizon.agent.connected.many_ago": "Konektado: %s na koneksyon ng ahente, huling utos %s s ang nakalipas",
|
||||
"horizon.agent.waiting": "Naghihintay ng ahente.",
|
||||
"horizon.agent.off": "Naka-off: hindi maabot ng mga ahente ang larong ito.",
|
||||
"horizon.agent.session_opened": "Binuksan para sa session na ito ng program na nagsimula ng laro.",
|
||||
"horizon.agent.socket": "Socket: %s (kopyahin ang mga detalye para sa buong path nito)",
|
||||
"horizon.agent.local_only": "Lokal lamang: mga ahente sa computer na ito, hindi sa network.",
|
||||
"Hides models behind opaque blocks. Entities update. Off with custom packs.": "Itinatago ang mga modelo sa likod ng mga opaque na bloke. Pag-update ng mga entity. I-off gamit ang mga custom na pack.",
|
||||
"horizon.extras.repro_keys": "Pagre-record ng mga shortcut",
|
||||
"horizon.extras.repro_keys.tooltip": "Ang F3+R ay nagsisimula o huminto sa isang repro recording at ang F3+E ay nagsusulat ng bundle nito. Naka-off bilang default: kinokopya ng isang recording ang mundo.",
|
||||
"horizon.agent.record_session": "Simulan ang Pagre-record ng Session",
|
||||
"horizon.agent.record_stop": "Ihinto ang Pagre-record ng Session",
|
||||
"horizon.agent.export_repro": "I-export ang Repro Bundle",
|
||||
"horizon.repro.started": "Nagsimula ang pagre-record; Itinigil ito ng F3+R at isusulat ang bundle.",
|
||||
"horizon.repro.stopped": "Nahinto ang pagre-record: %s",
|
||||
"horizon.repro.no_recording": "Wala pang recording na ie-export.",
|
||||
"horizon.repro.replay_started": "Nagsimula ang replay: %s",
|
||||
"horizon.pack.addInfo": "Magdagdag ng resource pack mula sa Modrinth",
|
||||
"horizon.pack.addWorking": "Tanong ni Modrinth...",
|
||||
"horizon.pack.addNone": "Walang nakitang mga resource pack",
|
||||
"horizon.pack.addTitle": "Magdagdag ng Resource Pack",
|
||||
"horizon.pack.install": "I-install",
|
||||
"horizon.pack.installing": "Pag-install",
|
||||
"horizon.pack.installed": "Naka-install",
|
||||
"horizon.pack.search": "Maghanap",
|
||||
"horizon.pack.searchHint": "Maghanap sa Modrinth...",
|
||||
"horizon.pack.filters": "Mga filter",
|
||||
"horizon.pack.filter.realistic": "Makatotohanan",
|
||||
"horizon.pack.filter.vanillaLike": "Parang vanilla",
|
||||
"horizon.pack.addFailed": "Hindi maidagdag ang pack: %s",
|
||||
"horizon.extras.header.cosmetics": "Mga pampaganda",
|
||||
"horizon.extras.cosmetics_mine": "Aking mga pampaganda",
|
||||
"horizon.extras.cosmetics_mine.tooltip": "Nakatago: makikita ka ng bawat Horizon na manlalaro nang wala ang iyong mga pampaganda, kasama mo. Ang parehong switch bilang Wardrobe ng launcher.",
|
||||
"horizon.extras.cosmetics_others": "Mga pampaganda ng ibang manlalaro",
|
||||
"horizon.extras.cosmetics_others.tooltip": "Ano ang isinusuot ng iba pang Horizon na manlalaro: lahat, mga istilo lang ng name tag nila, o wala. Nakatago, ang laro ay hindi nagtatanong kung ano ang kanilang isinusuot.",
|
||||
"horizon.extras.cosmetics_auras": "Mga aura at landas ng iba",
|
||||
"horizon.extras.cosmetics_auras.tooltip": "Mga aura at trail na isinusuot ng ibang mga manlalaro. Naka-off bilang default.",
|
||||
"horizon.extras.cosmetics.shown": "Ipinakita",
|
||||
"horizon.extras.cosmetics.hidden": "Nakatago",
|
||||
"horizon.extras.cosmetics.name_tags": "Mga name tag lang"
|
||||
}
|
||||
@@ -0,0 +1,478 @@
|
||||
{
|
||||
"horizon.options.controller": "Stýrari",
|
||||
"horizon.options.three_d_skin_layers": "3D húðløg",
|
||||
"horizon.options.vibration": "Ristingar",
|
||||
"horizon.options.adaptive_triggers": "Tillagandi útloysarar",
|
||||
"horizon.options.lightbar": "Ljósstrika",
|
||||
"horizon.options.look_sensitivity": "Hyggjuviðkvæmi",
|
||||
"horizon.options.invert_x": "Umvending av hyggjan X",
|
||||
"horizon.options.invert_y": "Umvending av hyggjan Y",
|
||||
"horizon.options.sneak_button": "Sníkiknøttur",
|
||||
"horizon.options.move_deadzone": "Deyðaøki fyri flyting",
|
||||
"horizon.options.look_deadzone": "Deyðaøki fyri hyggjan",
|
||||
"horizon.options.button_glyphs": "Knappaglyfur",
|
||||
"horizon.options.on_screen_keyboard": "Lyklaborð á skjánum",
|
||||
"horizon.options.chat_delay": "Kjakseinking",
|
||||
"horizon.options.lightbar.health": "Heilsa",
|
||||
"horizon.options.lightbar.dimension": "Mát",
|
||||
"horizon.options.unavailable": "Hesin hentleikin er ikki tøkur enn í Horizon.",
|
||||
"horizon.options.search": "Leiti innstillingar...",
|
||||
"horizon.pages.shader_packs": "Skuggapakkar",
|
||||
"horizon.pages.shader_options": "Skuggamøguleikar",
|
||||
"horizon.pages.controller": "Innstillingar av stýriskipanini",
|
||||
"horizon.pages.controller_binds": "Stýriskipanin bindur",
|
||||
"horizon.pages.extras": "Horizon Eyka",
|
||||
"horizon.pages.settings": "Horizon Innstillingar",
|
||||
"horizon.pages.agent": "AI umboðsmaður",
|
||||
"horizon.split.leave": "Far",
|
||||
"horizon.pages.split_settings": "Innstillingar fyri býtisskjálvta",
|
||||
"horizon.pages.split_profiles": "Hvør spælir?",
|
||||
"horizon.pages.split_setup": "Uppseting av býttum skermi",
|
||||
"horizon.pages.music": "Tónleikur",
|
||||
"horizon.pages.music.menu": "Matskrá",
|
||||
"horizon.pages.music.overworld": "Yvirheimur",
|
||||
"horizon.pages.music.creative": "Skapandi",
|
||||
"horizon.pages.music.underwater": "Undir vatni",
|
||||
"horizon.pages.music.end": "Endin",
|
||||
"horizon.pages.music.boss": "Stjóri",
|
||||
"horizon.pages.music.credits": "Eindir",
|
||||
"horizon.pages.music.overworld_biomes": "Yvirheimslívfrøði",
|
||||
"horizon.pages.music.nether_biomes": "Neðra lívfrøði",
|
||||
"horizon.pages.music.end_biomes": "Endalívfrøði",
|
||||
"horizon.pages.music.other": "Annar tónleikur",
|
||||
"horizon.pages.music.empty": "Eingi tónleikaløg: ljóðini í spælinum eru ikki heintað.",
|
||||
"horizon.pages.music.tooltip": "Innbygdu løgini, eftir støðu: spæl eitt nú, ella sløkk nøkur so spælið steðgar við at tína tað.",
|
||||
"horizon.pages.settings.tooltip": "Horizon's egnu innstillingar: grafikkur, stýringar, eyka og mods.",
|
||||
"horizon.pages.graphics.tooltip": "Grafikkur, einfalt: hvør innstilling sigur hvat hon kostar.",
|
||||
"horizon.pages.graphics_advanced.tooltip": "Hvør grafikk innstilling, Horizon's íroknað, við hvat hvør kostar.",
|
||||
"horizon.pages.controller.tooltip": "Stýringar: teirra knappar, prikkar, vibratiónir og valmyndanavigatión.",
|
||||
"horizon.pages.extras.tooltip": "Valfrí viðbót, alt sløkt sum standard: spælið heldur seg vanilju til tú tendrar eitt.",
|
||||
"horizon.pages.agent.tooltip": "Lat tín egna AI umboðsmann spæla: horizon-ctl og MCP klientar á hesi telduni.",
|
||||
"horizon.pages.split_profiles.tooltip": "Hvør spælir: ein profilur goymdur í hesi spælimappuni.",
|
||||
"horizon.pages.split_setup.tooltip": "Vindeyguni og skjálvtar, og hvør spælir hvar.",
|
||||
"horizon.pages.shader_packs.tooltip": "Skuggapakkar úr skuggapakka mappuni: Horizon's egnu og teir í skugganum/ sniðinum. Eitt rennur í senn.",
|
||||
"horizon.pages.mods.tooltip": "Mods gjørd til Horizon, úr horizon-mods mappuni. Hvør koyrir í einum sandkassa og heldur seg sløkt, til tú tendrar hann.",
|
||||
"horizon.pages.open.graphics": "Grafikkur...",
|
||||
"horizon.pages.open.graphics_advanced": "Framkomin grafikkur...",
|
||||
"horizon.pages.open.shader_packs": "Skuggapakkar...",
|
||||
"horizon.pages.open.controller": "Innstillingar av stýrinum...",
|
||||
"horizon.pages.open.split_setup": "Býttur skermur...",
|
||||
"horizon.pages.open.extras": "Eyka...",
|
||||
"horizon.pages.open.agent": "AI umboðsmaður...",
|
||||
"horizon.pages.open.horizon_graphics": "Horizon Grafikkur...",
|
||||
"horizon.pages.open.controller_binds": "Stýri bindur...",
|
||||
"horizon.pages.open.horizon_settings": "Horizon Innstillingar...",
|
||||
"horizon.pages.open.music": "Tónleikur...",
|
||||
"horizon.mods.empty": "Ongar mods: set .hmod fílur í horizon-mods mappuna",
|
||||
"horizon.mods.stopped": " (Steðgað)",
|
||||
"horizon.mods.not_built": " (Ikki bygt)",
|
||||
"horizon.mods.dev": " (Menning)",
|
||||
"horizon.mods.settings": "Innstillingar",
|
||||
"horizon.mods.in_world": " (lat heimin broytast)",
|
||||
"horizon.mods.open_folder": "Opna Mod mappuna",
|
||||
"horizon.shader_packs.empty": "Ongar skuggapakkar: set teir í mappuna skuggapakkar",
|
||||
"horizon.shader_options.open": "Skuggamøguleikar...",
|
||||
"horizon.shader_options.profile": "Vangamynd",
|
||||
"horizon.shader_options.loading": "Lesa møguleikarnar í skuggapakkanum...",
|
||||
"horizon.agent.copy_details": "Avrita sambandsupplýsingar",
|
||||
"horizon.multiplayer.join": "Ver við",
|
||||
"horizon.multiplayer.cancel_reconnecting": "Avlýs aftursamband",
|
||||
"horizon.multiplayer.join_friend": "Melda teg til ein vin",
|
||||
"horizon.multiplayer.invite_code": "Boðkoda",
|
||||
"horizon.multiplayer.relay": "Stafett (valfrítt)",
|
||||
"Preset": "Forsett",
|
||||
"LOD Distance": "LOD Fjarstøða",
|
||||
"Far Detail": "Fjar Detalja",
|
||||
"Cave Culling": "Helladráp",
|
||||
"Entity Culling": "Eindarskurður",
|
||||
"Chunk Updates": "Klumpardagføringar",
|
||||
"Upload Budget": "Send fíggjarætlan upp",
|
||||
"Fog": "Toka",
|
||||
"Weather": "Veður",
|
||||
"Animated Textures": "Livandi tekstur",
|
||||
"Present Mode": "Núverandi háttur",
|
||||
"Frame Pacing": "Rammu tempo",
|
||||
"Worker Threads": "Arbeiðsmannatráðir",
|
||||
"Resolution Scale": "Upploysnisstiga",
|
||||
"Anti-aliasing": "Anti-alias",
|
||||
"Upscaling": "Uppstilling",
|
||||
"Paper White": "Pappír Hvítt",
|
||||
"Peak Brightness": "Toppljósstyrki",
|
||||
"Black Level": "Svart stig",
|
||||
"UI Brightness": "UI Ljósstyrki",
|
||||
"Battery Mode": "Battarístilling",
|
||||
"Graphics API": "Grafikk API",
|
||||
"Translucent Batching": "Gjøgnumskygd bólking",
|
||||
"Full Detail Distance": "Full detaljufjarstøða",
|
||||
"On": "Á",
|
||||
"Off": "Sløkt",
|
||||
"Custom": "Sersniðgivið",
|
||||
"Performance": "Avrikið",
|
||||
"Quality": "Góðska",
|
||||
"Ultra Performance": "Ultra avrikið",
|
||||
"Native": "Upprunaligt",
|
||||
"Reduced": "Minkað",
|
||||
"Efficient": "Effektivur",
|
||||
"Precise": "Nágreinilig",
|
||||
"Auto (VSync)": "Sjálvvirkandi (Vsamskipan)",
|
||||
"Mailbox": "Postkassi",
|
||||
"Immediate": "Beinanvegin",
|
||||
"FPS and Graph": "FPS og Graf",
|
||||
"No cost": "Eingin kostnaður",
|
||||
"Low cost": "Lágur kostnaður",
|
||||
"Medium cost": "Miðalkostnaður",
|
||||
"High cost": "Høgur kostnaður",
|
||||
"Saves time": "Sparir tíð",
|
||||
"Graphics": "Grafikkur",
|
||||
"Done": "Liðugt",
|
||||
"This feature is not yet available in Horizon.": "Hesin hentleikin er ikki tøkur enn í Horizon.",
|
||||
"Your display or system doesn't offer HDR output.": "Tín skjár ella skipan bjóðar ikki HDR útgang.",
|
||||
"Turn HDR on to use it.": "Tendra HDR fyri at brúka tað.",
|
||||
"Your GPU or graphics API doesn't support it.": "Tín GPU ella grafikk API stuðlar ikki tí.",
|
||||
"%s chunks": "%s bitar",
|
||||
"%s per frame": "%s fyri hvørja rammu",
|
||||
"%s MiB/frame": "%s MiB/ramma",
|
||||
"%s KiB/frame": "%s KiB/ramma",
|
||||
"Auto (%s)": "Sjálvvirkandi (%s)",
|
||||
"Full-detail terrain range. LOD Distance can extend local worlds farther.": "Full-detalja lendisøki. LOD Fjarstøða kann víðka lokalar heimar longur.",
|
||||
"Coarse distant terrain in local worlds. Integrated GPUs stop at 128 chunks.": "Grovt fjarskotið lendi í lokalum heimum. Integreraðir GPU'ar steðga á 128 klumpum.",
|
||||
"Reduced draws far terrain coarser: faster on this integrated GPU.": "Minkað dregur langt lendi grovari: skjótari á hesum integreraða GPU.",
|
||||
"Reduced draws far terrain coarser, for GPUs it slows down.": "Minkað dregur langt lendið grovari, fyri GPU'ar tað bremsar.",
|
||||
"Field of view. Wider shows more terrain at once.": "Sjónarringur. Breiðari vísir meira lendi í senn.",
|
||||
"Caps frames per second; a cap saves power and heat.": "Hettar rammur um sekundið; hetta sparir streym og hita.",
|
||||
"Waits for the display's refresh: no tearing, a little latency.": "Bíðar eftir at skjárin verður uppdateraður: einki rív, eitt sindur av latency.",
|
||||
"Size of menus and the HUD.": "Stødd á valmyndum og HUD.",
|
||||
"Sets the options below together. Changing one makes it Custom.": "Setur valmøguleikarnar niðanfyri saman. At broyta eitt ger tað Custom.",
|
||||
"Lava, fire and sunlight shine brighter than white. Needs an HDR display.": "Lava, eldur og sólarljós skína bjartari enn hvítt. Tørvar HDR skjálvta.",
|
||||
"Your display's darkest black. 0 for OLED; LCDs glow a little.": "Skjárin hjá tær er myrkast svartur. 0 fyri OLED; LCD-skjáir glógva eitt sindur.",
|
||||
"How bright highlights get. Auto: the peak your system reports.": "Hvussu bjart hæddarpunkt fáa. Sjálvvirkandi: toppurin, sum tín skipan greiðir frá.",
|
||||
"How bright white paper and menus look. Auto: your desktop's white.": "Hvussu ljóst hvítt pappír og matskráir síggja út. Sjálvvirkandi: skriviborðið er hvítt.",
|
||||
"How bright the HUD and menus are, against paper white.": "Hvussu ljós HUD og valmyndir eru, móti pappírshvítum.",
|
||||
"How far mobs, crops and machines keep working. CPU time.": "Hvussu langt mobbar, grøðir og maskinur halda fram at virka. CPU tíð.",
|
||||
"How far away mobs and items are drawn, as a share of normal.": "Hvussu langt burtur mobbar og lutir eru drignir, sum partur av vanligum.",
|
||||
"Skips terrain hidden behind closed sections. Off costs a lot.": "Sleppur lendi goymt aftan fyri stongdar partar. Av kostar nógv.",
|
||||
"Hides entities behind opaque blocks.": "Goymir eindir aftan fyri ógjøgnumskygdar blokkar.",
|
||||
"No entity occlusion culling.": "Eingin eind okklusión avlíving.",
|
||||
"CPU occlusion test runs this frame.": "CPU okklusiónsroynd koyrir hesa rammuna.",
|
||||
"Occlusion checks run on a worker thread.": "Okklusiónskanningar koyra á einum arbeiðstráði.",
|
||||
"Meshed sections uploaded per frame. Lower is smoother while loading.": "Meskaðir partar lagdir upp fyri hvørja rammu. Lægri er slættari meðan tú lastar.",
|
||||
"Soft shadows in corners. Costs chunk building time only.": "Mjúkir skuggar í hornum. Kostar klump byggitíð einans.",
|
||||
"Smaller copies of block textures for distant terrain: less shimmer.": "Smærri eintøk av blokktekstur til fjarskotið lendi: minni glitrandi.",
|
||||
"Blends grass and water colours across biomes when building chunks.": "Blanda gras- og vatnlitir tvørtur um biomur, tá ið bygt verður klumpar.",
|
||||
"Cloud layer: off, flat (fast) or 3D (fancy).": "Skýlag: av, flatt (skjótt) ella 3D (fancy).",
|
||||
"How far clouds reach, in chunks.": "Hvussu langt skýggj røkka, í bitum.",
|
||||
"Draws the sky, sun, moon and stars.": "Teknar himmal, sól, mána og stjørnur.",
|
||||
"Distance fog. Off shows the edge of the loaded world.": "Fjarstøðumjørki. Off vísir kantin á lastaða heiminum.",
|
||||
"Draws rain and snow.": "Dregur regn og hálku.",
|
||||
"How far rain and snow fall around you.": "Hvussu langt regn og hálku fellur rundan um teg.",
|
||||
"How many particles effects spawn.": "Hvussu nógvar partiklar ávirkanir gýta.",
|
||||
"Round shadows under mobs and items.": "Rundir skuggar undir mobbum og lutum.",
|
||||
"Leaves with see-through gaps. Off draws them solid.": "Bløð við gjøgnumskygdum holum. Off dregur teir solid.",
|
||||
"Sorts water and glass more exactly behind each other.": "Sorterar vatn og glas meira nágreiniliga aftanfyri hvørt annað.",
|
||||
"Which chunk rebuilds wait for the frame: none, nearby or yours.": "Hvør klumpi umbyggir bíða eftir rammuni: eingin, nærhendis ella tín.",
|
||||
"Animates water, lava, fire and other moving textures.": "Lívgar vatn, lava, eld og aðrar rørandi tekstur.",
|
||||
"World pixels per screen pixel. Below 100% is faster on the GPU.": "Heimspixel fyri hvønn skermpixel. Undir 100% er skjótari á GPU.",
|
||||
"Smooths jagged edges. FXAA: softer. TAA: smoothest, moving things may trail.": "Slættar snøggaðar kantar. FXAA: mjúkari. TAA: slættast, rørandi ting kunnu slóða.",
|
||||
"Renders the world smaller and rebuilds it with TAA. Faster, softer.": "Ger heimin minni og umbyggir hann við TAA. Skjótari, mjúkari.",
|
||||
"HDR output on an HDR display: lava, fire and sunlight shine brighter.": "HDR útgangur á HDR skjái: lava, eldur og sólarljós skína ljósari.",
|
||||
"How frames reach the screen while VSync is off.": "Hvussu rammur røkka skerminum meðan VSync er sløkt.",
|
||||
"Efficient sleeps until the next frame; Precise spins, like vanilla.": "Effektivur svevur til næstu rammu; Nágreinilig snúningar, sum vanilja.",
|
||||
"Fills the screen (borderless).": "Fyllir skermin (markleysur).",
|
||||
"Brightens dark places.": "Lýsir myrk støð.",
|
||||
"Lowers the frame rate when minimised, or idle too.": "Lækkar rammufrekvensin tá hon er minkað, ella idle eisini.",
|
||||
"Sways the view while walking.": "Sveiggjar útsýnið, meðan tú gongur.",
|
||||
"Fades newly loaded chunks in.": "Doyvir nýlastaðar klumpar í.",
|
||||
"Darkens the screen's edges.": "Myrkir kantarnar á skerminum.",
|
||||
"Shows when the world saves.": "Vísir tá heimurin bjargar.",
|
||||
"Shows attack cooldown.": "Vísir álopskøling.",
|
||||
"60 FPS cap (30 in menus or unfocused), half the workers: less power.": "60 FPS hetta (30 í valmyndum ella ófokuserað), helvtin av arbeiðsfólkunum: minni kraft.",
|
||||
"Threads that generate, light and mesh chunks. Next start.": "Tráðir sum framleiða, ljós og mesh klumpar. Næsta byrjan.",
|
||||
"Vulkan, then DirectX 12 (Windows) or OpenGL (Linux) where it fails. Next start.": "Vulkan, síðani DirectX 12 (Windows) ella OpenGL (Linux) har tað miseydnast. Næsta byrjan.",
|
||||
"Water and glass in one buffer: fewer draw calls, a bit more VRAM. Next start.": "Vatn og glas í einum bufferi: færri draw call, eitt sindur meira VRAM. Næsta byrjan.",
|
||||
"Mesh data sent to the GPU per frame. Lower is smoother while loading.": "Mesh dátur sendar til GPU pr rammu. Lægri er slættari meðan tú lastar.",
|
||||
"Frame rate and frame times over the game, with a graph.": "Rammufrekvens og rammutíðir yvir spælið, við grafi.",
|
||||
"horizon.multiplayer.finding_friend": "At finna heimin hjá tínum vini...",
|
||||
"horizon.multiplayer.not_signed_in": "Hesin ambætarin er í online-stilling. Rita inn við tínari Microsoft kontu í Horizon launcher fyri at melda teg til.",
|
||||
"horizon.multiplayer.invalid_address": "Ógyldug ambætaraadressa: %s",
|
||||
"horizon.multiplayer.connected_friend_direct": "Samband beinleiðis við tín vin...",
|
||||
"horizon.multiplayer.connected_friend_relay": "Samband við tín vin gjøgnum stafettina...",
|
||||
"General": "Alment",
|
||||
"Advanced": "Framkomin",
|
||||
"Undo": "Angra",
|
||||
"Search options": "Leitimøguleikar",
|
||||
"Shortcut": "Snarvegur",
|
||||
"Distance": "Fjarstøða",
|
||||
"Display": "Sýn",
|
||||
"Interface": "Grunnflata",
|
||||
"Sky and weather": "Himmal og veður",
|
||||
"Lighting and entities": "Ljós og eindir",
|
||||
"Textures": "Tekstur",
|
||||
"Image": "Mynd",
|
||||
"Chunk loading": "Innlesing av klumpi",
|
||||
"Culling": "Avlíving",
|
||||
"Power": "Vald",
|
||||
"Frames": "Rammur",
|
||||
"Overlay": "Yvirlag",
|
||||
"Output": "Útflutningur",
|
||||
"Brightness": "Ljósstyrki",
|
||||
"How far you see, the window and the HUD.": "Hvussu langt tú sært, vindeygað og HUD.",
|
||||
"The sky and weather, lighting, textures and the image.": "Himmalin og veðrið, ljós, tekstur og ímyndin.",
|
||||
"Chunk loading, culling and power use.": "Klumplasting, avlíving og orkunýtsla.",
|
||||
"How frames reach the screen, and the performance overlay.": "Hvussu rammur røkka skerminum, og framførslan yvirleggur.",
|
||||
"Brighter-than-white output on an HDR display.": "Ljósari-enn-hvítur útgangur á einum HDR-skjálvta.",
|
||||
"Results for \"%s\"": "Úrslit fyri \"%s\"",
|
||||
"No settings match.": "Ongar innstillingar passa.",
|
||||
"horizon.title.not_affiliated": "Ikki tilknýtt Mojang ella Microsoft",
|
||||
"horizon.extras.header.lighting": "Ljós",
|
||||
"horizon.extras.header.third_person": "Triði persónur",
|
||||
"horizon.extras.header.particles": "Partiklar",
|
||||
"horizon.extras.header.inventory": "Goymsla",
|
||||
"horizon.extras.header.chat": "Prát",
|
||||
"horizon.extras.header.multiplayer": "Fleirspælari",
|
||||
"horizon.extras.header.sound": "Ljóð",
|
||||
"horizon.extras.header.menus": "Valmyndir",
|
||||
"horizon.extras.fullbright": "Fullljós",
|
||||
"horizon.extras.dynamic_lights": "Dynamisk ljós",
|
||||
"horizon.extras.own_name_tag": "Egið navnamerki",
|
||||
"horizon.extras.hide_block_particles": "Goym blokkbrotspartiklar",
|
||||
"horizon.extras.auto_reconnect": "Sjálvvirkandi endursamband",
|
||||
"horizon.extras.ui_sound_reserve": "Halt rásir til brúkaragjøgnumførsljóð",
|
||||
"horizon.extras.music_page": "Tónleikasíða",
|
||||
"horizon.extras.mouse_tweaks": "Mús Tweaks stýringar",
|
||||
"horizon.extras.mouse_tweaks_wheel": "Rulluhjólið flytur lutir",
|
||||
"horizon.extras.sort": "Sortera knappar",
|
||||
"horizon.extras.sort_key": "Sortera lykil",
|
||||
"horizon.extras.no_ai": "Eingin AI",
|
||||
"horizon.extras.agent_control": "Umboðsmannsstýring",
|
||||
"horizon.extras.discord_presence": "Discord Rík nærvera",
|
||||
"horizon.extras.splitscreen": "Býtt skermur",
|
||||
"horizon.extras.chat_animation": "Slætt prát",
|
||||
"horizon.extras.chat_indicator": "Boðvísari",
|
||||
"horizon.extras.wheel_cycles_settings": "Rulluhjólið broytir innstillingar",
|
||||
"horizon.extras.pack_browser": "Tilfeingispakka kaga",
|
||||
"horizon.extras.fullbright.tooltip": "Vís blokkar og eindir við fullum ljósi, eisini í myrkum økjum.",
|
||||
"horizon.extras.dynamic_lights.tooltip": "Kyndlar og aðrar ljóskeldur, sum verða hildnar, sleptar ella í eldi, tendra blokkarnar rundan um seg.",
|
||||
"horizon.extras.own_name_tag.tooltip": "Vísir títt navn omanfyri høvdið í triðja persóni, sum aðrir spælarar síggja tað. Dult tá ambætarin goymir nøvnini á tínum liði ella tú ert ósjónligur.",
|
||||
"horizon.extras.hide_block_particles.tooltip": "Goymir ruskpartiklarnar, sum spreingjast úr einum brotnum blokki og sláa seg saman av tí, tú námar. Aðrar partiklar halda seg.",
|
||||
"horizon.extras.auto_reconnect.tooltip": "Meldar seg aftur til ein ambætara eftir mist samband ella endurbyrjan, ongantíð eftir spark ella bann.",
|
||||
"horizon.extras.ui_sound_reserve.tooltip": "Ljóð í heiminum lata 16 av teimum 247 ljóðrásunum vera fríar, so ein flóðaldur av teimum (ein stór spreinging) kann ikki tøgna valmyndaklikk.",
|
||||
"horizon.extras.music_page.tooltip": "Music & Sounds fær eina Music... síðu: spæl eitthvørt innbygt løg nú, ella sløkk eitt, so spælið steðgar við at velja tað. Einki broytist, fyrr enn tú sløkkir eitt lag.",
|
||||
"horizon.extras.mouse_tweaks.tooltip": "Høgra-drag setur eitt per slot, vinstra-drag savnar tann hilda lutin, Shift + vinstra-drag flytur hvørt slot.",
|
||||
"horizon.extras.mouse_tweaks_wheel.tooltip": "Niður sendir ein lutur av slitinum til hina síðuna, upp fær ein aftur.",
|
||||
"horizon.extras.sort.tooltip": "Sorterar goymsluna, kistur, tunnur, ender kistur og shulker kassar í kreativari flipa raðfylgju, letur saman stakkar.",
|
||||
"horizon.extras.sort_key.tooltip": "Sorterar partin undir markørinum. Trýst, trýst síðani á ein knøtt; Flýggjan loysir tað.",
|
||||
"horizon.extras.no_ai.tooltip": "Goymir og sløkkir hvønn AI-funktión: agentstýring, horizon-ctl og MCP-ambætarar. Rotarin á sjósetingini eisini.",
|
||||
"horizon.extras.agent_control.tooltip": "Tín egni AI umboðsmaður kann spæla hetta spælið gjøgnum horizon-ctl ella ein MCP klient, á hesi telduni bert.",
|
||||
"horizon.extras.discord_presence.tooltip": "Vísir Spæla Horizon á tínum Discord profili meðan Discord koyrir: valmyndir, einspælari ella fleirspælari, víddina og tíðina, sum er spæld. Ongantíð eitt heimsnavn ella adressa á einum ambætara.",
|
||||
"Calibrate...": "Kalibrera...",
|
||||
"Calibrate Anyway...": "Kalibrera allíkavæl...",
|
||||
"Use Automatic Setup": "Brúka sjálvvirkandi uppseting",
|
||||
"Shortcut: %s": "Snarvegur: %s",
|
||||
"Next": "Næsta",
|
||||
"HDR Calibration %s/%s: %s": "HDR-kalibrering %s/%s: %s",
|
||||
"Sets the three below full screen, one test picture at a time.": "Setur tey trý niðanfyri fullan skerm, eina royndarmynd í senn.",
|
||||
"A key that opens this screen from the game. Not bound at first.": "Ein lykil, sum letur upp hendan skermin frá spælinum. Ikki bundin í fyrstuni.",
|
||||
"Your display didn't say how bright it gets: calibrate to set it up.": "Títt skjálvti segði ikki, hvussu ljóst tað blívur: kalibrera fyri at seta tað upp.",
|
||||
"Already set up for your display. Only calibrate if HDR looks wrong.": "Longu sett upp til tín skjálvta. Kalibrera bert um HDR sær skeivt út.",
|
||||
"Puts Peak Brightness and Paper White back to your display's setup.": "Setur Toppljósstyrki og Pappírshvítt aftur til uppsetingina á skjánum.",
|
||||
"Set up for your display. Leave on Auto unless it looks wrong.": "Set upp til tína skjálvta. Lat vera við Auto uttan so at tað sær skeivt út.",
|
||||
"Lower it until the logo just disappears into the black.": "Lækka tað til búmerkið bara hvørvur í svarta.",
|
||||
"Raise it until the logo just disappears into the bright square.": "Lyft tað upp, til búmerkið bara hvørvur inn í ljósa torgið.",
|
||||
"Make the card a white that's comfortable to look at for a long time, in the light you play in.": "Ger kortið til eitt hvítt, sum er behagligt at hyggja at leingi, í ljósinum tú spælir í.",
|
||||
"horizon.splitscreen.profiles.forget": "Gloym",
|
||||
"horizon.splitscreen.profiles.create": "Stovna",
|
||||
"horizon.splitscreen.profiles.you": " - tú",
|
||||
"horizon.splitscreen.profiles.forget_named": "Gloym %s .",
|
||||
"horizon.splitscreen.profiles.previous": "Fyrra",
|
||||
"horizon.splitscreen.profiles.next": "Næsta",
|
||||
"horizon.splitscreen.profiles.new_button": "Nýggj vangamynd...",
|
||||
"horizon.splitscreen.profiles.forget_title": "Gloym vangamyndina?",
|
||||
"horizon.splitscreen.profiles.forget_leaves": "Tað fer úr listanum hjá hesum instansi.",
|
||||
"horizon.splitscreen.profiles.forget_kept": "Heimsframgongd og karmar eru hildnir.",
|
||||
"horizon.splitscreen.profiles.new_title": "Nýggj vangamynd",
|
||||
"horizon.splitscreen.profiles.name_hint": "Navn (3 til 16 bókstavir, siffur, _)",
|
||||
"horizon.splitscreen.profiles.switch_title": "Skift vangamynd",
|
||||
"horizon.splitscreen.profiles.offline_note": "Offline profilar hoyra til hesa instans",
|
||||
"horizon.splitscreen.profiles.move": "Flyt har tú spælir",
|
||||
"horizon.splitscreen.profiles.move_place": "Flyt har tú spælir: %s .",
|
||||
"horizon.friends.title": "Spæl við vinum",
|
||||
"horizon.friends.hint": "Vinir líma kotuna eftir Vinir knøttin á tittulskjálvtanum, í Beinleiðis sambandi ella á Spæla síðuni á sjósetaranum.",
|
||||
"horizon.friends.copied": "Avritað",
|
||||
"horizon.friends.copy_code": "Avritskotu",
|
||||
"horizon.friends.stop_sharing": "Steðga við at deila",
|
||||
"horizon.friends.none_yet": "Eingir vinir her enn.",
|
||||
"horizon.friends.here_now": "Her nú: %s",
|
||||
"horizon.friends.share_intro": "Deil hendan heimin aftanfyri eina boðkotu: hon letur upp fyri LAN, og vinir á internetinum melda seg til við koduni. Eingin servari hjá okkum er við.",
|
||||
"horizon.friends.start_sharing": "Byrja at deila",
|
||||
"horizon.friends.troubleshooting": "Trupulleikaloysn...",
|
||||
"horizon.friends.stopped": "Steðgaði við at deila boðkotuna.",
|
||||
"horizon.friends.short_code_changed": "Onkur bleiv við at royna eina skeiva stutta kodu, so hon broyttist.",
|
||||
"horizon.friends.wrong_code": "Onkur royndi eina skeiva kodu.",
|
||||
"horizon.friends.code_ready": "Tín boðkoda er klár: Spælvalmynd, Spæl við vinum. Kopiera tað og send tað til tínar vinir.",
|
||||
"horizon.friends.share_failed": "Kundi ikki deila heimin: %s",
|
||||
"horizon.friends.finding_route": "At finna útav, hvussu vinir kunnu røkka tær...",
|
||||
"horizon.osk.shift": "Vakt",
|
||||
"horizon.osk.space": "Rúm",
|
||||
"horizon.osk.delete": "Strika",
|
||||
"horizon.osk.type": "Slag",
|
||||
"horizon.osk.symbols": "Tákn",
|
||||
"horizon.osk.close": "Lat aftur",
|
||||
"horizon.extras.chat_animation.tooltip": "Ein nýggj kjaklinja rennur inn frá vinstru, meðan hon doyvir inn, í staðin fyri at síggja heil út.",
|
||||
"horizon.extras.chat_indicator.tooltip": "Litaða strikan til vinstru á kjaklinju.",
|
||||
"horizon.extras.wheel_cycles_settings.tooltip": "Rulluhjólið yvir einum knøtti í innstillingunum broytir virðið, eins og í vanilju. Av, hjólið rullar bara listan.",
|
||||
"horizon.extras.pack_browser.tooltip": "Vel Tilfeingispakkar fær ein Legg til knøtt, sum leitar Modrinth og setur ein pakka upp í tína pakka mappu. Sløkt, spælið ongantíð kontaktar Modrinth.",
|
||||
"horizon.extras.splitscreen.tooltip": "Í einum heimi kann ein annar stýrari melda seg til sum nýggjur spælari: trýst á A tá tað spyr, vel síðani ein profil og hvar tú skalt spæla.",
|
||||
"horizon.splitscreen.setup.monitor": "Skjár %s",
|
||||
"horizon.splitscreen.setup.monitor_unknown": "ein skjár",
|
||||
"horizon.splitscreen.setup.window": "Vindeyga %s",
|
||||
"horizon.splitscreen.setup.new_window": "Nýtt vindeyga",
|
||||
"horizon.splitscreen.setup.fill_monitor": "Fyll út %s",
|
||||
"horizon.splitscreen.setup.done": "Liðugt",
|
||||
"horizon.splitscreen.setup.on": "Á",
|
||||
"horizon.splitscreen.setup.off": "Sløkt",
|
||||
"horizon.splitscreen.setup.player": "Spælari %s",
|
||||
"horizon.splitscreen.setup.revert": "Aftur",
|
||||
"horizon.splitscreen.setup.apply": "Søk",
|
||||
"horizon.splitscreen.setup.warning.empty_main": "Eingin spælir í Vindeyga 1: tað goymir seg",
|
||||
"horizon.splitscreen.setup.warning.empty_close": "Eingin spælir í Vindeyga %s: tað letur aftur á Søk",
|
||||
"horizon.splitscreen.setup.warning.empty_new": "Eingin spælir í Vindeyga %s: tað letur ikki upp",
|
||||
"horizon.splitscreen.setup.warning.on_main": "Vindeyga %s fyllir skjálvtan hjá Vindeyga 1: tess spælarar spæla í Vindeyga 1",
|
||||
"horizon.splitscreen.setup.warning.unplugged": "Skjárin hjá Vindeyga %s er ikki tengdur: spælarar hansara spæla í Vindeyga 1",
|
||||
"horizon.splitscreen.setup.status.off": "Splitskermur er sløktur.",
|
||||
"horizon.splitscreen.setup.status.enable_hint": "Tendra tað, og trýst síðani á ein knøtt á einum øðrum stýriskipanum í einum heimi.",
|
||||
"horizon.splitscreen.setup.status.join_hint": "Trýst á A fyri at melda teg til og vel ein vangamynd.",
|
||||
"horizon.splitscreen.setup.status.idle": "Býtt skermur í tómgongd",
|
||||
"horizon.splitscreen.setup.status.alone": "Ongin annar lokalur leikari.",
|
||||
"horizon.splitscreen.setup.status.solo_controls": "Solo stýringar og afturmeldingar hjá stýraranum eru óbroyttar.",
|
||||
"horizon.splitscreen.setup.window_empty": "Vindeyga %s: tómt",
|
||||
"horizon.splitscreen.setup.note.select": "Trýst á ein spælara, ella drag hann til eitt vindeyga ella ein skjálvta.",
|
||||
"horizon.splitscreen.setup.note.apply": "Søk um at spæla soleiðis, Vend aftur fyri at angra.",
|
||||
"horizon.splitscreen.setup.note.place": "Hvar skal %s spæla?",
|
||||
"horizon.splitscreen.setup.this_player": "hesin spælarin",
|
||||
"horizon.splitscreen.setup.switch_disabled": "Splitscreen sløkkir, tá hini eru farin (teirra steðgvalmynd).",
|
||||
"horizon.splitscreen.setup.window_place": "Vindeyga %s (%s av %s)",
|
||||
"horizon.splitscreen.setup.names": "Nøvn",
|
||||
"horizon.splitscreen.setup.identify": "Eyðmerkja",
|
||||
"horizon.splitscreen.setup.layout.two": "2 deiling: %s",
|
||||
"horizon.splitscreen.setup.layout.three": "3 deiling: %s",
|
||||
"horizon.splitscreen.setup.layout.two.1": "Lið um lið",
|
||||
"horizon.splitscreen.setup.layout.two.2": "Ovast og niðast",
|
||||
"horizon.splitscreen.setup.layout.three.0": "Eitt breitt omaná",
|
||||
"horizon.splitscreen.setup.layout.three.1": "Ein høgur til vinstru",
|
||||
"horizon.splitscreen.setup.layout.three.2": "Lið um lið",
|
||||
"horizon.splitscreen.setup.help.player": "Trýst ella drag %s fyri at flyta tey.",
|
||||
"horizon.splitscreen.setup.help.layout_auto": "%s (lið um lið, tá vindeygað er breitt). Trýst fyri at broyta.",
|
||||
"horizon.splitscreen.setup.help.layout": "%s. Trýst fyri at broyta.",
|
||||
"horizon.splitscreen.setup.help.switch": "Splitscreen til hesa telduna, tendrað ella sløkt.",
|
||||
"horizon.splitscreen.setup.help.identify": "Sýningin hjá hvørjum spælara vísir hvørjum vindeyga hann er í.",
|
||||
"horizon.splitscreen.setup.help.names": "Navnið á hvørjum leikara í horninum av teirra útsýni.",
|
||||
"horizon.splitscreen.setup.help.revert": "Angra broytingarnar, sum ikki eru galdandi enn.",
|
||||
"horizon.splitscreen.setup.help.apply": "Spæl soleiðis, sum kortið vísir.",
|
||||
"horizon.splitscreen.setup.help.unchanged": "Enn er einki broytt.",
|
||||
"horizon.splitscreen.setup.give_up_pad": "Gev upp Pad",
|
||||
"horizon.splitscreen.prompt.controller_connected": "Stýriskipan er knýtt at",
|
||||
"horizon.splitscreen.prompt.controller_disconnected": "Stýriskipanin er slitin",
|
||||
"horizon.splitscreen.prompt.controller_disconnected.hint": "Set tað í samband aftur, ella trýst á ein knøtt á einum øðrum",
|
||||
"horizon.splitscreen.prompt.join.one": "%s vil vera við",
|
||||
"horizon.splitscreen.prompt.join.many": "%s stýrarar vilja melda seg til",
|
||||
"horizon.splitscreen.prompt.join.yes": "Ver við",
|
||||
"horizon.splitscreen.prompt.join.as_p1": "Spæl sum P1.",
|
||||
"horizon.splitscreen.prompt.join.no": "Nei",
|
||||
"horizon.splitscreen.prompt.lost": "%s: stýriskipanin er slitin",
|
||||
"horizon.splitscreen.prompt.lost.use_another": "Brúka eitt annað",
|
||||
"horizon.splitscreen.prompt.lost.leave": "Far",
|
||||
"horizon.splitscreen.setup.help.give_up_pad": "Tín stýrimaður steðgar við at koyra teg og fær bjóðað at melda seg til (A).",
|
||||
"horizon.splitscreen.setup.note.held_at": "%s til %s: A sleppur tí her, B leggur tað aftur.",
|
||||
"horizon.splitscreen.setup.note.held": "%s tikið upp: vinstri/høgri tekur har, A sleppur, B leggur tað aftur.",
|
||||
"horizon.splitscreen.online_only": "Hesin ambætarin er í online-stilling: offline-profilar kunnu ikki melda seg til hann, hvør spælari hevur brúk fyri síni egnu Minecraft kontu.",
|
||||
"horizon.splitscreen.own_account": "Hesin ambætarin hevur brúk fyri hvørjum spælara egna Minecraft kontu",
|
||||
"horizon.splitscreen.local_only": "Aðrir spælarar kunnu bert melda seg til hendan ambætaran við egnari Minecraft konto: offline profilar spæla í tínum heimi, á LAN ella á einum ambætara á tínum lokala neti.",
|
||||
"Hides models behind opaque blocks. Async checks off-thread; entities tick.": "Goymir modellir aftan fyri ógjøgnumskygdar blokkar. Async kannar uttan fyri tráðin; eindir merkja.",
|
||||
"Block Entities": "Blokk eindir",
|
||||
"Shulker Boxes": "Shulker kassar",
|
||||
"Reuses settled boxes; lid movement stays animated.": "Endurnýtir avgjørdar kassar; lok rørslan heldur seg lívgaða.",
|
||||
"Signs": "Tekin",
|
||||
"Reuses sign text until text, light, or font changes.": "Endurnýtir skeltitekst, til tekstur, ljós ella skriftslag broytist.",
|
||||
"Decorated Pots": "Prýddir grýtur",
|
||||
"Reuses still pots; break wobble and sherd changes redraw.": "Endurnýtir enn pottar; bróta vagga og skerv broytingar umtekna.",
|
||||
"Bells": "Klokkur",
|
||||
"Reuses still bells; ringing stays animated.": "Endurnýtir enn klokkur; ringja heldur seg lívgandi.",
|
||||
"Chests": "Kistur",
|
||||
"Reuses closed chests; moving lids stay animated.": "Endurnýtir lukkaðar kistur; rørandi lok halda seg lívgað.",
|
||||
"Banners": "Merki",
|
||||
"Reuses poles; flags and pattern layers still update.": "Endurnýtir stong; flagg og mynsturløg dagførast enn.",
|
||||
"Copper Golem Statues": "Kopar Golem standmyndir",
|
||||
"Reuses statue geometry until its block state changes.": "Endurnýtir standmyndageometri til blokktilstandurin broytist.",
|
||||
"Leaf Culling": "Blaðsláttur",
|
||||
"Every leaf face. Vanilla's fancy leaves.": "Hvørt blað andlit. Snøggu bløðini hjá vanilju.",
|
||||
"Distant Plant Dither": "Fjarplantu Dither",
|
||||
"Keeps fine plants in high-res packs from fading far away.": "Heldur fínum plantum í háupploysn pakkum frá at doyggja langt burtur.",
|
||||
"Screenshot Quality": "Skjálvtagóðska",
|
||||
"F2 screenshots at this many times the game's resolution. Higher takes longer.": "F2 skermmyndir við hesi nógvar ferðir spælsins upploysn. Hægri tekur longri tíð.",
|
||||
"Frame Generation": "Rammuættarlið",
|
||||
"Shows a made-up frame between each two real ones: smoother, a little more lag.": "Vísir eina gjørda rammu millum hvønn tveir veruligar: slættari, eitt sindur meira lag.",
|
||||
"Shadow Cache": "Skuggagoymsla",
|
||||
"Reuses the pack shadow map when sun, view and world match. Off by default.": "Endurnýtir pakka skuggakortið, tá sól, útsýni og heimur passa saman. Sløkt sum standard.",
|
||||
"Find BlueMap": "Finn Blákort",
|
||||
"On servers, finds their BlueMap web map for far terrain. Next join.": "Á ambætarum, finnur teirra BlueMap vevkort fyri fjart lendi. Næsta melda teg til.",
|
||||
"BlueMap Radius": "Blákortradius",
|
||||
"How far around you BlueMap tiles are downloaded. Next join.": "Hvussu langt rundan um teg eru BlueMap flísar heintaðar. Næsta melda teg til.",
|
||||
"Synchronous": "Samsvarandi",
|
||||
"Asynchronous": "Asynkront",
|
||||
"Solid": "Fast",
|
||||
"Solid Aggressive": "Solid ágangandi",
|
||||
"Hollow": "Holur",
|
||||
"Leaves fully inside a canopy draw solid: fewer see-through layers.": "Bløðini fult inni í einum høli draga fast: færri gjøgnumskygd løg.",
|
||||
"Leaves with one open side draw solid too: faster, chunkier edges.": "Bløð við einari opnari síðu draga eisini fast: skjótari, klumpigari kantar.",
|
||||
"Drops faces between leaves: faster, but gaps look through.": "Dropar andlit millum bløð: skjótari, men hol hyggja ígjøgnum.",
|
||||
"Hotbar: Previous Slot": "Hotbar: Fyrri pláss",
|
||||
"Hotbar: Next Slot": "Heitbarr: Næsta pláss",
|
||||
"horizon.agent.connected.one": "Samband: 1 umboðssamband",
|
||||
"horizon.agent.connected.many": "Samband: %s umboðssamband",
|
||||
"horizon.agent.connected.one_ago": "Samband: 1 agentsamband, seinasta skipan %s s síðani",
|
||||
"horizon.agent.connected.many_ago": "Samband: %s agentsamband, seinasta skipan fyri %s s síðani",
|
||||
"horizon.agent.waiting": "Bíða eftir umboði.",
|
||||
"horizon.agent.off": "Off: umboðsmenn kunnu ikki røkka hesum dystinum.",
|
||||
"horizon.agent.session_opened": "Opnað fyri hesa setuna av skránni sum byrjaði dystin.",
|
||||
"horizon.agent.socket": "Socket: %s (kopiera smálutirnar fyri alla leiðina)",
|
||||
"horizon.agent.local_only": "Einans lokalt: umboðsmenn á hesi telduni, ongantíð netið.",
|
||||
"%s nits": "%s nitur",
|
||||
"Auto (%s nits)": "Sjálvvirkandi (%s nits)",
|
||||
"%.2f nits": "%.2f nitur",
|
||||
"Hides models behind opaque blocks. Entities update. Off with custom packs.": "Goymir modellir aftan fyri ógjøgnumskygdar blokkar. Eindir dagførast. Av við sersniðgivnum pakkum.",
|
||||
"horizon.extras.repro_keys": "Upptøka av snarvegum",
|
||||
"horizon.extras.repro_keys.tooltip": "F3+R byrjar ella steðgar eina repro upptøku og F3+E skrivar sína bingju. Sløkt sum standard: ein upptøka avritar heimin.",
|
||||
"horizon.agent.record_session": "Byrja upptøkuløtuna",
|
||||
"horizon.agent.record_stop": "Steðga upptøku",
|
||||
"horizon.agent.export_repro": "Útflyt Repro bingju",
|
||||
"horizon.repro.started": "Upptøkan byrjað; F3+R steðgar tí og skrivar bingjuna.",
|
||||
"horizon.repro.stopped": "Upptøkan steðgað: %s",
|
||||
"horizon.repro.bundle": "Repro bingja: %s",
|
||||
"horizon.repro.error": "Endurtøka: %s",
|
||||
"horizon.repro.no_recording": "Eingin upptøka er at útflyta enn.",
|
||||
"horizon.repro.replay_started": "Endurtøka byrjað: %s",
|
||||
"horizon.pack.addInfo": "Legg tilfeingispakka frá Modrinth",
|
||||
"horizon.pack.addWorking": "Spyrja Modrinth...",
|
||||
"horizon.pack.addNone": "Eingin tilfeingispakki funnin",
|
||||
"horizon.pack.addTitle": "Legg ein tilfeingispakka til",
|
||||
"horizon.pack.install": "Set upp",
|
||||
"horizon.pack.installing": "Seta upp",
|
||||
"horizon.pack.installed": "Sett upp",
|
||||
"horizon.pack.search": "Leita",
|
||||
"horizon.pack.searchHint": "Leita Modrinth...",
|
||||
"horizon.pack.filters": "Filtur",
|
||||
"horizon.pack.filter.realistic": "Realistiskt",
|
||||
"horizon.pack.filter.simplistic": "Einfalt",
|
||||
"horizon.pack.filter.vanillaLike": "Vaniljulíknandi",
|
||||
"horizon.pack.addFailed": "Pakkin kundi ikki leggjast afturat: %s .",
|
||||
"horizon.extras.header.cosmetics": "Snyrtivøra",
|
||||
"horizon.extras.cosmetics_mine": "Mítt kosmetikk",
|
||||
"horizon.extras.cosmetics_mine.tooltip": "Dult: hvør Horizon spælari sær teg uttan títt kosmetikk, tú eisini. Sama rotari sum Klædnaskápið hjá sjósetaranum.",
|
||||
"horizon.extras.cosmetics_others": "Kosmetikkur hjá øðrum spælarum",
|
||||
"horizon.extras.cosmetics_others.tooltip": "Hvat aðrir Horizon spælarar eru í: alt, bara teirra navnamerkjastílar, ella einki. Dult spyr spælið ongantíð, hvat tey eru í.",
|
||||
"horizon.extras.cosmetics_auras": "Aura og slóðir hjá øðrum",
|
||||
"horizon.extras.cosmetics_auras.tooltip": "Auras og slóðir aðrir spælarar bera. Sløkt sum standard.",
|
||||
"horizon.extras.cosmetics.shown": "Víst",
|
||||
"horizon.extras.cosmetics.hidden": "Dult",
|
||||
"horizon.extras.cosmetics.name_tags": "Einans navnamerki"
|
||||
}
|
||||
Loaded 100 of 619 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user