Skip to content

Commit dfa0e8f

Browse files
committed
Add unknown texture for textures not in assets (pack.png for example)
1 parent b6c9b43 commit dfa0e8f

6 files changed

Lines changed: 297 additions & 238 deletions

File tree

packobf/src/file_parser.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use std::str::FromStr;
1818
use std::sync::Arc;
1919
use tokio::sync::mpsc::UnboundedSender;
2020
use tokio::sync::watch::Sender;
21+
use crate::resource_pack::files::unknowntexture::UnknownTexture;
2122

2223
pub fn parse_resource_pack_files(
2324
logger: &UnboundedSender<LogMessage>,
@@ -210,9 +211,13 @@ fn parse_resource_pack_file(
210211
}
211212
} else if name.ends_with(".mcmeta") {
212213
json_file(logger, pack, name, content);
213-
} else if name.ends_with(".png") && get_type(name) == Some("textures") {
214-
let (overlay, identifier) = parse_path(name);
215-
pack.texture(Texture::new(overlay, identifier, content.to_owned()));
214+
} else if name.ends_with(".png") {
215+
if get_type(name) == Some("textures") {
216+
let (overlay, identifier) = parse_path(name);
217+
pack.texture(Texture::new(overlay, identifier, content.to_owned()));
218+
} else {
219+
pack.unknown_texture(UnknownTexture::new(name.as_str(), content.to_owned()))
220+
}
216221
} else if name.ends_with(".vsh") || name.ends_with(".fsh") || name.ends_with(".glsl") {
217222
pack.shader(Shader::new(
218223
name.to_owned(),

packobf/src/lib.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ use std::sync::Arc;
3737
use tokio::sync::mpsc::UnboundedSender;
3838
use tokio::sync::watch::Sender;
3939
use zip::ZipArchive;
40+
use crate::resource_pack::files::unknowntexture::UnknownTexture;
4041

4142
pub fn process_zip(
4243
input_bytes: Vec<u8>,
@@ -186,7 +187,7 @@ fn add_item_to_archive(
186187
match item {
187188
ResourcePackItem::Texture(o) => {
188189
o.optimize(options, logger, cache);
189-
writer.add_file(name.as_str(), o.bytes.as_slice(), options, cache)
190+
writer.add_file(name.as_str(), o.unknown_texture.bytes.as_slice(), options, cache)
190191
}
191192
ResourcePackItem::Shader(o) => {
192193
o.optimize(options, logger);
@@ -223,6 +224,9 @@ fn add_item_to_archive(
223224
ResourcePackItem::Atlas(o) => {
224225
writer.add_file(name.as_str(), o.to_string().as_bytes(), options, cache)
225226
}
227+
ResourcePackItem::UnknownTexture(o) => {
228+
writer.add_file(name.as_str(), o.bytes.as_slice(), options, cache)
229+
}
226230
}?;
227231
Ok(())
228232
}
@@ -235,6 +239,12 @@ fn collect_files(pack: Arc<ResourcePack>) -> Vec<(String, ResourcePackItem)> {
235239
ResourcePackItem::Texture(kv.value().clone()),
236240
)
237241
});
242+
let unknown_texture_iter = pack.unknown_textures.par_iter().map(|kv| {
243+
(
244+
kv.key().clone(),
245+
ResourcePackItem::UnknownTexture(kv.value().clone()),
246+
)
247+
});
238248
let shader_iter = pack.shaders.par_iter().map(|kv| {
239249
(
240250
kv.key().clone(),
@@ -295,6 +305,7 @@ fn collect_files(pack: Arc<ResourcePack>) -> Vec<(String, ResourcePackItem)> {
295305
});
296306

297307
texture_iter
308+
.chain(unknown_texture_iter)
298309
.chain(shader_iter)
299310
.chain(model_iter)
300311
.chain(json_iter)
@@ -329,6 +340,7 @@ pub enum Progress {
329340
#[derive(Clone, Debug)]
330341
enum ResourcePackItem {
331342
Texture(Texture),
343+
UnknownTexture(UnknownTexture),
332344
Shader(Shader),
333345
Json(Json),
334346
Model(Model),

packobf/src/resource_pack/files/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ pub mod font;
99
pub mod sound;
1010
pub mod sound_definitions;
1111
pub mod atlas;
12+
pub mod unknowntexture;
Lines changed: 20 additions & 234 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,15 @@
1-
use crate::cache::{Cache, ItemType};
2-
use crate::options::{Compression, Options};
3-
use crate::png::{crc, recoverer};
1+
use crate::cache::Cache;
2+
use crate::options::Options;
3+
use crate::resource_pack::files::unknowntexture::UnknownTexture;
44
use crate::resource_pack::identifier::Identifier;
5-
use crate::LogLevel::{Info, Warning};
6-
use crate::{options, profile_scope, LogMessage};
7-
use once_cell::sync::Lazy;
8-
use oxipng::{indexset, optimize_from_memory, Deflater, FilterStrategy, StripChunks};
9-
use sha2::{Digest, Sha256};
10-
use std::time::Duration;
5+
use crate::LogMessage;
116

127
// textures are referenced in `models`, `items` and `font`
138
#[derive(Clone, Debug)]
149
pub struct Texture {
1510
pub overlay: String,
1611
pub identifier: Identifier,
17-
pub bytes: Vec<u8>,
12+
pub unknown_texture: UnknownTexture
1813
}
1914

2015
impl Texture {
@@ -23,10 +18,22 @@ impl Texture {
2318
identifier: impl Into<Identifier>,
2419
bytes: Vec<u8>,
2520
) -> Self {
21+
let overlay = overlay.into();
22+
let prefix = if overlay.is_empty() {
23+
"".to_string()
24+
} else {
25+
format!("{}/", overlay)
26+
};
27+
let identifier = identifier.into();
28+
let path = format!(
29+
"{}assets/{}/textures/{}.png",
30+
prefix, identifier.namespace, identifier.path
31+
);
32+
let unknown_texture = UnknownTexture::new(path, bytes);
2633
Self {
2734
overlay: overlay.into(),
2835
identifier: identifier.into(),
29-
bytes,
36+
unknown_texture,
3037
}
3138
}
3239

@@ -36,232 +43,11 @@ impl Texture {
3643
logger: &tokio::sync::mpsc::UnboundedSender<LogMessage>,
3744
cache: &Option<Cache>,
3845
) {
39-
self.bytes = Self::cache_or_optimize(&self.bytes, options, logger, cache, &self.path());
40-
if options.corrupt_png_files {
41-
match crc::modify_png_crcs(&self.bytes) {
42-
Ok(bytes) => {
43-
self.bytes = bytes;
44-
}
45-
Err(e) => {
46-
let _ = logger.send(LogMessage {
47-
level: Warning,
48-
message: format!("Could not corrupt image '{}'. Error: {}", self.path(), e),
49-
});
50-
}
51-
}
52-
}
53-
}
54-
55-
fn cache_or_optimize(
56-
bytes: &[u8],
57-
options: &Options,
58-
logger: &tokio::sync::mpsc::UnboundedSender<LogMessage>,
59-
cache: &Option<Cache>,
60-
path: &str,
61-
) -> Vec<u8> {
62-
profile_scope!("cache_or_optimize::texture");
63-
if let Some(cache) = cache {
64-
let mut sha256 = Sha256::new();
65-
sha256.update(bytes);
66-
let hash: [u8; 32] = sha256.finalize().into();
67-
68-
if let Some(bytes) = cache
69-
.with_item(&hash, ItemType::Image, |it| {
70-
(it.compression as u8 >= options.compression.clone() as u8)
71-
.then(|| it.data.clone())
72-
})
73-
.flatten()
74-
{
75-
let _ = logger.send(LogMessage {
76-
level: Info,
77-
message: format!("Image '{}' was loaded from cache.", path),
78-
});
79-
return bytes;
80-
}
81-
}
82-
let oxipng_options = match options.compression {
83-
Compression::Simplest => &DEFAULT_OPTIONS,
84-
Compression::Normal => &NORMAL_OPTIONS,
85-
Compression::Max => &MAX_OPTIONS,
86-
};
87-
match optimize_from_memory(bytes, oxipng_options) {
88-
Ok(value) => {
89-
if let Some(cache) = cache {
90-
cache.add_item(
91-
bytes,
92-
&*value,
93-
options.compression.clone() as u8,
94-
ItemType::Image,
95-
)
96-
}
97-
value
98-
}
99-
Err(e) => {
100-
let _ = logger.send(LogMessage {
101-
level: Info,
102-
message: format!(
103-
"Could not optimize image '{}'. Trying to recover it. Error: {}",
104-
path, e
105-
),
106-
});
107-
match recoverer::recover_png(bytes) {
108-
Ok(value) => {
109-
let _ = logger.send(LogMessage {
110-
level: Info,
111-
message: format!("Image '{}' was recovered successfully.", path),
112-
});
113-
match optimize_from_memory(value.as_slice(), oxipng_options) {
114-
Ok(value) => {
115-
if let Some(cache) = cache {
116-
cache.add_item(
117-
bytes,
118-
&*value,
119-
options.compression.clone() as u8,
120-
ItemType::Image,
121-
)
122-
}
123-
value
124-
}
125-
Err(e) => {
126-
let _ = logger.send(LogMessage {
127-
level: Warning,
128-
message: format!(
129-
"Could not optimize image '{}'. Skipping optimization. Error: {}",
130-
path,
131-
e),
132-
});
133-
value
134-
}
135-
}
136-
}
137-
Err(e) => {
138-
let _ = logger.send(LogMessage {
139-
level: Warning,
140-
message: format!(
141-
"Could not recover image '{}'. Skipping optimization. Error: {}",
142-
path, e
143-
),
144-
});
145-
bytes.to_owned()
146-
}
147-
}
148-
}
149-
}
46+
self.unknown_texture.optimize(options, logger, cache);
15047
}
15148

15249
pub fn path(&self) -> String {
153-
let prefix = if self.overlay.is_empty() {
154-
"".to_string()
155-
} else {
156-
format!("{}/", self.overlay)
157-
};
158-
format!(
159-
"{}assets/{}/textures/{}.png",
160-
prefix, self.identifier.namespace, self.identifier.path
161-
)
50+
self.unknown_texture.path.clone()
16251
}
16352
}
16453

165-
/**
166-
Currently, only the `deflater` option changes, but some other options could be modified based on the compression wanted.
167-
*/
168-
//<editor-fold desc="Oxipng options" defaultstate="collapsed">
169-
static DEFAULT_OPTIONS: Lazy<oxipng::Options> = Lazy::new(|| oxipng::Options {
170-
fix_errors: true,
171-
force: false,
172-
filters: indexset! {
173-
FilterStrategy::NONE,
174-
FilterStrategy::SUB,
175-
FilterStrategy::UP,
176-
FilterStrategy::AVERAGE,
177-
FilterStrategy::PAETH,
178-
FilterStrategy::MinSum,
179-
FilterStrategy::Entropy,
180-
FilterStrategy::Bigrams,
181-
FilterStrategy::BigEnt,
182-
FilterStrategy::Brute {
183-
num_lines: 8,
184-
level: 12,
185-
},
186-
},
187-
interlace: Some(false),
188-
optimize_alpha: true,
189-
bit_depth_reduction: true,
190-
color_type_reduction: true,
191-
palette_reduction: true,
192-
grayscale_reduction: true,
193-
idat_recoding: true,
194-
scale_16: false,
195-
strip: StripChunks::All,
196-
deflater: Deflater::Libdeflater { compression: 6 }, // 6: default compression level
197-
fast_evaluation: false,
198-
timeout: Some(Duration::from_secs(3)),
199-
max_decompressed_size: None,
200-
});
201-
202-
static NORMAL_OPTIONS: Lazy<oxipng::Options> = Lazy::new(|| oxipng::Options {
203-
fix_errors: true,
204-
force: false,
205-
filters: indexset! {
206-
FilterStrategy::NONE,
207-
FilterStrategy::SUB,
208-
FilterStrategy::UP,
209-
FilterStrategy::AVERAGE,
210-
FilterStrategy::PAETH,
211-
FilterStrategy::MinSum,
212-
FilterStrategy::Entropy,
213-
FilterStrategy::Bigrams,
214-
FilterStrategy::BigEnt,
215-
FilterStrategy::Brute {
216-
num_lines: 8,
217-
level: 12,
218-
},
219-
},
220-
interlace: Some(false),
221-
optimize_alpha: true,
222-
bit_depth_reduction: true,
223-
color_type_reduction: true,
224-
palette_reduction: true,
225-
grayscale_reduction: true,
226-
idat_recoding: true,
227-
scale_16: false,
228-
strip: StripChunks::All,
229-
deflater: Deflater::Libdeflater { compression: 12 }, // 12: max compression level for libdeflater
230-
fast_evaluation: false,
231-
timeout: Some(Duration::from_secs(3)),
232-
max_decompressed_size: None,
233-
});
234-
235-
static MAX_OPTIONS: Lazy<oxipng::Options> = Lazy::new(|| oxipng::Options {
236-
fix_errors: true,
237-
force: false,
238-
filters: indexset! {
239-
FilterStrategy::NONE,
240-
FilterStrategy::SUB,
241-
FilterStrategy::UP,
242-
FilterStrategy::AVERAGE,
243-
FilterStrategy::PAETH,
244-
FilterStrategy::MinSum,
245-
FilterStrategy::Entropy,
246-
FilterStrategy::Bigrams,
247-
FilterStrategy::BigEnt,
248-
FilterStrategy::Brute {
249-
num_lines: 8,
250-
level: 12,
251-
},
252-
},
253-
interlace: Some(false),
254-
optimize_alpha: true,
255-
bit_depth_reduction: true,
256-
color_type_reduction: true,
257-
palette_reduction: true,
258-
grayscale_reduction: true,
259-
idat_recoding: true,
260-
scale_16: false,
261-
strip: StripChunks::All,
262-
deflater: Deflater::Zopfli(options::ZOPFLI_OPTIONS.to_owned()), // zopfli: best compression
263-
fast_evaluation: false,
264-
timeout: Some(Duration::from_secs(3)),
265-
max_decompressed_size: None,
266-
});
267-
//</editor-fold>

0 commit comments

Comments
 (0)