Skip to content

Commit

Permalink
- added autosave
Browse files Browse the repository at this point in the history
- added check for closing the window with unsaved tabs
- enter to drop held entry
- enter to select text
- added tooltip effect to make it more readable
- fixed bug with snbt editing keys not escaping
- added list as root node kind
- added bedrock's little endian nbt format
  • Loading branch information
RealRTTV committed Apr 23, 2024
1 parent cccddb4 commit 2e24bbb
Show file tree
Hide file tree
Showing 27 changed files with 1,376 additions and 311 deletions.
6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "nbtworkbench"
version = "1.2.6"
version = "1.3.0"
edition = "2021"
description = "A modern NBT Editor written in Rust designed for performance and efficiency."
license-file = "LICENSE"
Expand All @@ -16,7 +16,7 @@ categories = ["graphics", "rendering", "text-editors", "parser-implementations"]
#path = "src/main.rs"

# Windows Only
#[package.metadata.winres]
[package.metadata.winres]

[profile.release]
opt-level = 3
Expand Down Expand Up @@ -45,7 +45,6 @@ strip = false
debug = true

[build-dependencies]
zune-png = "0.4.10"
flate2 = "1.0.27"
winres = "0.1.12"

Expand All @@ -66,6 +65,7 @@ anyhow = "1.0.79"
lz4_flex = { version = "0.11.2", default-features = false, features = ["std", "nightly"] }
regex = "1.10.3"
glob = "0.3.1"
zune-png = { version = "0.4.10", features = [] }

[target.'cfg(target_os = "windows")'.dependencies]
winapi = { version = "0.3.9", features = [] }
Expand Down
3 changes: 0 additions & 3 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,8 @@ use std::io::Read;
use std::mem::MaybeUninit;

const UNICODE: &[u8] = include_bytes!("src/assets/build/unicode.hex");
const ATLAS: &[u8] = include_bytes!(r"src/assets/build/atlas.png");

fn main() {
{ write(r"src\assets\atlas.hex", zune_png::PngDecoder::new(ATLAS).decode_raw().unwrap()).unwrap(); }

{
let mut char_widths: [MaybeUninit<u8>; 56832] = MaybeUninit::uninit_array();
for (idx, maybe) in char_widths.iter_mut().enumerate() {
Expand Down
16 changes: 14 additions & 2 deletions src/assets.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
use std::cell::LazyCell;
use std::mem::ManuallyDrop;
use std::ops::Deref;
use zune_png::zune_core::options::DecoderOptions;
use crate::since_epoch;

use crate::vertex_buffer_builder::Vec2u;

pub const HEADER_SIZE: usize = 48;

pub const ATLAS: &[u8] = include_bytes!("assets/atlas.hex");
pub const ATLAS_ENCODED: &[u8] = include_bytes!("assets/atlas.png");
pub const ATLAS_WIDTH: usize = 256;
pub const ATLAS_HEIGHT: usize = 256;
pub const UNICODE_LEN: usize = 1_818_624;
Expand Down Expand Up @@ -58,6 +61,8 @@ pub const GZIP_FILE_TYPE_UV: Vec2u = Vec2u::new(48, 80);
pub const ZLIB_FILE_TYPE_UV: Vec2u = Vec2u::new(64, 80);
pub const SNBT_FILE_TYPE_UV: Vec2u = Vec2u::new(80, 80);
pub const MCA_FILE_TYPE_UV: Vec2u = Vec2u::new(96, 80);
pub const LITTLE_ENDIAN_NBT_FILE_TYPE_UV: Vec2u = Vec2u::new(152, 160);
pub const LITTLE_ENDIAN_HEADER_NBT_FILE_TYPE_UV: Vec2u = Vec2u::new(168, 160);
pub const OPEN_FOLDER_UV: Vec2u = Vec2u::new(112, 80);
pub const UNSELECTED_TOGGLE_ON_UV: Vec2u = Vec2u::new(0, 64);
pub const UNSELECTED_TOGGLE_OFF_UV: Vec2u = Vec2u::new(8, 64);
Expand Down Expand Up @@ -170,11 +175,18 @@ pub enum ZOffset {
HELD_ENTRY_Z = 210,
ALERT_Z = 240,
ALERT_TEXT_Z = 241,
TOOLTIP_Z = 250,
TOOLTIP_BLUR_Z = 254,
TOOLTIP_Z = 255,
}

pub use ZOffset::*;

static mut ATLAS_CELL: LazyCell<Vec<u8>> = LazyCell::new(|| zune_png::PngDecoder::new_with_options(ATLAS_ENCODED, DecoderOptions::new_fast().png_set_confirm_crc(false)).decode_raw().unwrap());

pub fn atlas() -> &'static [u8] {
unsafe { ATLAS_CELL.deref().as_slice() }
}

#[allow(clippy::cast_ptr_alignment)]
pub fn icon() -> Vec<u8> {
// error!("Hello, world!");
Expand Down
Binary file removed src/assets/atlas.hex
Binary file not shown.
Binary file added src/assets/atlas.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed src/assets/build/atlas.png
Binary file not shown.
23 changes: 6 additions & 17 deletions src/decoder.rs → src/be_decoder.rs
Original file line number Diff line number Diff line change
@@ -1,24 +1,27 @@
use std::intrinsics::likely;
use std::marker::PhantomData;

use compact_str::CompactString;
use crate::elements::compound::CompoundMap;
use crate::SortAlgorithm;

pub struct Decoder {
pub struct BigEndianDecoder<'a> {
pub data: *const u8,
end: *const u8,
sort: SortAlgorithm,
_marker: PhantomData<&'a ()>,
}

#[allow(improper_ctypes_definitions)]
impl Decoder {
impl<'a> BigEndianDecoder<'a> {
#[inline]
#[optimize(speed)]
pub const fn new(data: &[u8], sort: SortAlgorithm) -> Self {
pub const fn new(data: &'a [u8], sort: SortAlgorithm) -> Self {
Self {
end: unsafe { data.as_ptr().add(data.len()) },
data: data.as_ptr(),
sort,
_marker: PhantomData,
}
}

Expand All @@ -27,7 +30,6 @@ impl Decoder {
self.sort.sort(map)
}

#[inline]
#[optimize(speed)]
#[must_use]
pub fn assert_len(&self, remaining_len: usize) -> Option<()> {
Expand All @@ -39,59 +41,46 @@ impl Decoder {
}
}

#[inline]
#[optimize(speed)]
pub unsafe fn read_bytes<const N: usize>(&mut self) -> [u8; N] {
let array = self.data.cast::<[u8; N]>().read();
self.data = self.data.add(N);
array
}

#[inline]
#[optimize(speed)]
pub unsafe fn u8(&mut self) -> u8 { u8::from_be_bytes(self.read_bytes()) }

#[inline]
#[optimize(speed)]
pub unsafe fn u16(&mut self) -> u16 { u16::from_be_bytes(self.read_bytes()) }

#[inline]
#[optimize(speed)]
pub unsafe fn u32(&mut self) -> u32 { u32::from_be_bytes(self.read_bytes()) }

#[inline]
#[optimize(speed)]
pub unsafe fn u64(&mut self) -> u64 { u64::from_be_bytes(self.read_bytes()) }

#[inline]
#[optimize(speed)]
pub unsafe fn i8(&mut self) -> i8 { i8::from_be_bytes(self.read_bytes()) }

#[inline]
#[optimize(speed)]
pub unsafe fn i16(&mut self) -> i16 { i16::from_be_bytes(self.read_bytes()) }

#[inline]
#[optimize(speed)]
pub unsafe fn i32(&mut self) -> i32 { i32::from_be_bytes(self.read_bytes()) }

#[inline]
#[optimize(speed)]
pub unsafe fn i64(&mut self) -> i64 { i64::from_be_bytes(self.read_bytes()) }

#[inline]
#[optimize(speed)]
pub unsafe fn f32(&mut self) -> f32 { f32::from_be_bytes(self.read_bytes()) }

#[inline]
#[optimize(speed)]
pub unsafe fn f64(&mut self) -> f64 { f64::from_be_bytes(self.read_bytes()) }

#[inline]
#[optimize(speed)]
pub unsafe fn skip(&mut self, amount: usize) { self.data = self.data.add(amount); }

#[inline]
#[optimize(speed)]
pub unsafe fn string(&mut self) -> Option<CompactString> {
let len = self.u16() as usize;
Expand Down
4 changes: 2 additions & 2 deletions src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -251,8 +251,8 @@ pub fn reformat() -> ! {
}

let tab = workbench.tabs.remove(0);
if let FileFormat::Nbt | FileFormat::Snbt | FileFormat::Gzip | FileFormat::Zlib = tab.compression {} else {
error!("Tab had invalid file format {}", tab.compression.to_string());
if let FileFormat::Nbt | FileFormat::Snbt | FileFormat::Gzip | FileFormat::Zlib = tab.format {} else {
error!("Tab had invalid file format {}", tab.format.to_string());
}

let out = format.encode(&tab.value);
Expand Down
36 changes: 36 additions & 0 deletions src/copy_shader.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
use wgsl_inline::wgsl;

wgsl! {
struct VertexInput {
@location(0)
position: vec2<f32>
}

struct VertexOutput {
@builtin(position)
position: vec4<f32>,
@location(0)
uv: vec2<f32>,
}

@vertex
fn vertex(input: VertexInput) -> VertexOutput {
var output: VertexOutput;
output.position = vec4<f32>(input.position, 1.0 - (254.0 / 255.0), 1.0);
output.uv = vec2<f32>((input.position.x + 1.0) / 2.0, (1.0 - input.position.y) / 2.0);
return output;
}

@group(0)
@binding(0)
var texture: texture_2d<f32>;

@group(0)
@binding(1)
var texture_sampler: sampler;

@fragment
fn fragment(input: VertexOutput) -> @location(0) vec4<f32> {
return textureSample(texture, texture_sampler, input.uv);
}
}
4 changes: 2 additions & 2 deletions src/element_action.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use compact_str::CompactString;
use notify::{EventKind, PollWatcher, RecursiveMode, Watcher};
use uuid::Uuid;

use crate::{panic_unchecked, set_clipboard, FileUpdateSubscription};
use crate::{panic_unchecked, set_clipboard, FileUpdateSubscription, StrExt};
#[cfg(not(target_arch = "wasm32"))]
use crate::{FileUpdateSubscriptionType, assets::{OPEN_ARRAY_IN_HEX_UV, OPEN_IN_TXT}, since_epoch};
use crate::assets::{ACTION_WHEEL_Z, COPY_FORMATTED_UV, COPY_RAW_UV, SORT_COMPOUND_BY_NAME, SORT_COMPOUND_BY_TYPE};
Expand Down Expand Up @@ -287,7 +287,7 @@ impl ElementAction {
if let Some(key) = key.as_deref()
&& element.id() != NbtChunk::ID
{
if write!(&mut file, "{key}: ").is_err() { break 'm; }
if write!(&mut file, "{k}: ", k = if key.needs_escape() { format!("{key:?}") } else { key.to_owned() }).is_err() { break 'm; }
}
if write!(&mut file, "{element:#?}").is_err() { break 'm; }
drop(file);
Expand Down
60 changes: 54 additions & 6 deletions src/elements/array.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,26 @@
#[macro_export]
macro_rules! array {
($element_field:ident, $name:ident, $t:ty, $my_id:literal, $id:literal, $char:literal, $uv:ident, $element_uv:ident) => {
#[derive(Default)]
#[repr(C)]
pub struct $name {
values: Box<Vec<NbtElement>>,
max_depth: u32,
open: bool,
}

impl PartialEq for $name {
fn eq(&self, other: &Self) -> bool {
self.values == other.values
impl $name {
pub fn matches(&self, other: &Self) -> bool {
if self.values.len() != other.values.len() {
return false
}

for (a, b) in self.values.iter().zip(other.values.iter()) {
if !a.matches(b) {
return false
}
}

true
}
}

Expand Down Expand Up @@ -70,7 +79,7 @@ macro_rules! array {
}

#[inline]
pub fn from_bytes(decoder: &mut Decoder) -> Option<Self> {
pub fn from_be_bytes(decoder: &mut BigEndianDecoder) -> Option<Self> {
unsafe {
decoder.assert_len(4)?;
let len = decoder.u32() as usize;
Expand Down Expand Up @@ -101,12 +110,51 @@ macro_rules! array {
}

#[inline]
pub fn to_bytes(&self, writer: &mut UncheckedBufWriter) {
pub fn to_be_bytes(&self, writer: &mut UncheckedBufWriter) {
writer.write(&(self.len() as u32).to_be_bytes());
for entry in self.values.iter() {
writer.write(&Self::transmute(entry).to_be_bytes());
}
}

#[inline]
pub fn from_le_bytes(decoder: &mut LittleEndianDecoder) -> Option<Self> {
unsafe {
decoder.assert_len(4)?;
let len = decoder.u32() as usize;
decoder.assert_len(len * core::mem::size_of::<$t>())?;
let vec = alloc(Layout::array::<NbtElement>(len).unwrap_unchecked()).cast::<NbtElement>();
for idx in 0..len {
let mut element = NbtElement {
$element_field: core::mem::transmute(<$t>::from_le_bytes(
decoder
.data
.add(idx * core::mem::size_of::<$t>())
.cast::<[u8; core::mem::size_of::<$t>()]>()
.read(),
)),
};
element.id.id = $id;
vec.add(idx).write(element);
}
decoder.data = decoder.data.add(len * core::mem::size_of::<$t>());
let boxx = alloc(Layout::new::<Vec<NbtElement>>()).cast::<Vec<NbtElement>>();
boxx.write(Vec::from_raw_parts(vec, len, len));
Some(Self {
values: Box::from_raw(boxx),
open: false,
max_depth: 0,
})
}
}

#[inline]
pub fn to_le_bytes(&self, writer: &mut UncheckedBufWriter) {
writer.write(&(self.len() as u32).to_le_bytes());
for entry in self.values.iter() {
writer.write(&Self::transmute(entry).to_le_bytes());
}
}
}

impl $name {
Expand Down
Loading

0 comments on commit 2e24bbb

Please sign in to comment.