Skip to content

Commit

Permalink
Support for attachable item with custom model (#121)
Browse files Browse the repository at this point in the history
* Support for attachable item with custom model.

* Revert some changes.

* Revert some changes.

* Changes.

* Changes.

* Changes.

* this.

* Update CubeConverter.

* Invert if.

* Changes.
  • Loading branch information
Oryxel authored Sep 8, 2024
1 parent 5bdfda0 commit ed85285
Show file tree
Hide file tree
Showing 7 changed files with 210 additions and 4 deletions.
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ dependencies {
exclude group: "com.google.guava"
}
api "org.lz4:lz4-pure-java:1.8.0"
api("com.github.Oryxel:CubeConverter:859c2cfa71") {
api("com.github.Oryxel:CubeConverter:5ae1e90e4f") {
transitive = false
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* This file is part of ViaBedrock - https://github.com/RaphiMC/ViaBedrock
* Copyright (C) 2023-2024 RK_01/RaphiMC and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.raphimc.viabedrock.api.model.resourcepack;

import com.viaversion.viaversion.util.Key;
import net.raphimc.viabedrock.ViaBedrock;
import net.raphimc.viabedrock.protocol.storage.ResourcePacksStorage;
import org.oryxel.cube.model.bedrock.data.BedrockAttachableData;
import org.oryxel.cube.parser.bedrock.data.BedrockAttachableSerializer;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;

public class AttachableDefinitions {

private final Map<String, AttachableDefinition> attachables = new HashMap<>();

public AttachableDefinitions(final ResourcePacksStorage resourcePacksStorage) {
for (ResourcePack pack : resourcePacksStorage.getPackStackBottomToTop()) {
for (String attachablePath : pack.content().getFilesDeep("attachables/", ".json")) {
try {
final BedrockAttachableData attachableData = BedrockAttachableSerializer.deserialize(pack.content().getString(attachablePath));
final String identifier = Key.namespaced(attachableData.identifier());
this.attachables.put(identifier, new AttachableDefinition(identifier, attachableData));
} catch (Throwable e) {
ViaBedrock.getPlatform().getLogger().log(Level.WARNING, "Failed to parse attachable definition " + attachablePath + " in pack " + pack.packId(), e);
}
}
}
}

public Map<String, AttachableDefinition> attachables() {
return Collections.unmodifiableMap(this.attachables);
}

public record AttachableDefinition(String identifier, BedrockAttachableData attachableData) {
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,4 @@ public Map<String, BedrockGeometry> entityModels() {
return Collections.unmodifiableMap(this.entityModels);
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import net.raphimc.viabedrock.protocol.data.ProtocolConstants;
import net.raphimc.viabedrock.protocol.model.BedrockItem;
import net.raphimc.viabedrock.protocol.model.ItemEntry;
import net.raphimc.viabedrock.protocol.rewriter.resourcepack.CustomAttachableResourceRewriter;
import net.raphimc.viabedrock.protocol.rewriter.resourcepack.CustomItemTextureResourceRewriter;
import net.raphimc.viabedrock.protocol.storage.ResourcePacksStorage;
import net.raphimc.viabedrock.protocol.types.BedrockTypes;
Expand Down Expand Up @@ -147,12 +148,17 @@ public Item javaItem(final BedrockItem bedrockItem) {
} else {
data.set(StructuredDataKey.ITEM_NAME, TextUtil.stringToNbt(resourcePacksStorage.getTexts().get("item." + Key.stripMinecraftNamespace(identifier) + ".name")));
}
if (itemDefinition.iconComponent() != null && resourcePacksStorage.isLoadedOnJavaClient()) {

if (resourcePacksStorage.getAttachables().attachables().containsKey(identifier) && resourcePacksStorage.isLoadedOnJavaClient()) {
data.set(StructuredDataKey.CUSTOM_MODEL_DATA, CustomAttachableResourceRewriter.getCustomModelData("attachable_" + identifier + "_default"));
javaItem = new StructuredItem(BedrockProtocol.MAPPINGS.getJavaItems().get(Key.namespaced(CustomAttachableResourceRewriter.ITEM)), bedrockItem.amount(), data);
} else if (itemDefinition.iconComponent() != null && resourcePacksStorage.isLoadedOnJavaClient()) {
data.set(StructuredDataKey.CUSTOM_MODEL_DATA, CustomItemTextureResourceRewriter.getCustomModelData(itemDefinition.iconComponent()));
javaItem = new StructuredItem(BedrockProtocol.MAPPINGS.getJavaItems().get(Key.namespaced(CustomItemTextureResourceRewriter.ITEM)), bedrockItem.amount(), data);
} else {
data.set(StructuredDataKey.LORE, new Tag[]{TextUtil.stringToNbt("§7[ViaBedrock] Custom item: " + identifier)});
javaItem = new StructuredItem(BedrockProtocol.MAPPINGS.getJavaItems().get("minecraft:paper"), bedrockItem.amount(), data);
}
javaItem = new StructuredItem(BedrockProtocol.MAPPINGS.getJavaItems().get(Key.namespaced(CustomItemTextureResourceRewriter.ITEM)), bedrockItem.amount(), data);
} else {
ViaBedrock.getPlatform().getLogger().log(Level.WARNING, "Missing bedrock -> java item mapping for " + identifier);
data.set(StructuredDataKey.ITEM_NAME, TextUtil.stringToNbt("§cMissing item: " + identifier));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import com.viaversion.viaversion.libs.gson.JsonObject;
import net.raphimc.viabedrock.api.model.resourcepack.ResourcePack;
import net.raphimc.viabedrock.protocol.data.ProtocolConstants;
import net.raphimc.viabedrock.protocol.rewriter.resourcepack.CustomAttachableResourceRewriter;
import net.raphimc.viabedrock.protocol.rewriter.resourcepack.CustomEntityResourceRewriter;
import net.raphimc.viabedrock.protocol.rewriter.resourcepack.CustomItemTextureResourceRewriter;
import net.raphimc.viabedrock.protocol.rewriter.resourcepack.GlyphSheetResourceRewriter;
Expand All @@ -32,6 +33,7 @@ public static ResourcePack.Content bedrockToJava(final ResourcePacksStorage reso

GlyphSheetResourceRewriter.apply(resourcePacksStorage, javaContent);
CustomItemTextureResourceRewriter.apply(resourcePacksStorage, javaContent);
CustomAttachableResourceRewriter.apply(resourcePacksStorage, javaContent);
CustomEntityResourceRewriter.apply(resourcePacksStorage, javaContent);

javaContent.putJson("pack.mcmeta", createPackManifest());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
/*
* This file is part of ViaBedrock - https://github.com/RaphiMC/ViaBedrock
* Copyright (C) 2023-2024 RK_01/RaphiMC and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.raphimc.viabedrock.protocol.rewriter.resourcepack;

import com.google.common.collect.Lists;
import com.viaversion.viaversion.libs.gson.JsonArray;
import com.viaversion.viaversion.libs.gson.JsonObject;
import com.viaversion.viaversion.util.GsonUtil;
import net.raphimc.viabedrock.api.model.resourcepack.AttachableDefinitions;
import net.raphimc.viabedrock.api.model.resourcepack.ResourcePack;
import net.raphimc.viabedrock.api.util.StringUtil;
import net.raphimc.viabedrock.protocol.storage.ResourcePacksStorage;
import org.oryxel.cube.converter.FormatConverter;
import org.oryxel.cube.model.bedrock.BedrockGeometry;
import org.oryxel.cube.model.java.ItemModelData;
import org.oryxel.cube.parser.java.JavaModelSerializer;

import java.awt.image.BufferedImage;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

public class CustomAttachableResourceRewriter {

public static final String ITEM = "leather";

public static void apply(final ResourcePacksStorage resourcePacksStorage, final ResourcePack.Content javaContent) {
final Map<Integer, JsonObject> overridesMap = new TreeMap<>();

for (Map.Entry<String, AttachableDefinitions.AttachableDefinition> entry : resourcePacksStorage.getAttachables().attachables().entrySet()) {
for (String bedrockPath : entry.getValue().attachableData().textures().values()) {
final String javaPath = "attachable_texture/" + StringUtil.makeIdentifierValueSafe(bedrockPath.replace("textures/", ""));
for (ResourcePack pack : resourcePacksStorage.getPackStackTopToBottom()) {
final ResourcePack.Content bedrockContent = pack.content();
final BufferedImage texture = bedrockContent.getShortnameImage(bedrockPath);
if (texture == null) continue;

javaContent.putImage("assets/viabedrock/textures/item/" + javaPath + ".png", texture);
break;
}
}

final AttachableDefinitions.AttachableDefinition attachableDefinition = entry.getValue();
for (Map.Entry<String, String> modelEntry : attachableDefinition.attachableData().geometries().entrySet()) {
final BedrockGeometry bedrockGeometry = resourcePacksStorage.getModels().entityModels().get(modelEntry.getValue());
if (bedrockGeometry == null) continue;
if (!attachableDefinition.attachableData().textures().containsKey(modelEntry.getKey())) continue;

final String javaTexturePath = "attachable_texture/" + StringUtil.makeIdentifierValueSafe(
attachableDefinition.attachableData().textures().get(modelEntry.getKey()).replace("textures/", ""));

final List<ItemModelData> cubeConverterItemModels = Lists.newArrayList(FormatConverter.bedrockToJava("viabedrock:item/" +
javaTexturePath, bedrockGeometry));

// It doesn't matter even if there is multiple models, it's item so only 1 model is supported.
if (cubeConverterItemModels.size() < 1) continue;
ItemModelData model = cubeConverterItemModels.get(0);
if (model == null) continue;

String json = JavaModelSerializer.serialize(model).toString();
if (json == null || json.isEmpty()) continue;
JsonObject object = GsonUtil.getGson().fromJson(json.trim(), JsonObject.class);

// Scaling up the model...
JsonObject display = new JsonObject();
JsonArray scaling = new JsonArray();
scaling.add(model.scale());
scaling.add(model.scale());
scaling.add(model.scale());

JsonObject value = new JsonObject();
value.add("scale", scaling);

display.add("firstperson_righthand", value);
display.add("firstperson_lefthand", value);
display.add("thirdperson_righthand", value);
display.add("thirdperson_lefthand", value);
display.add("head", value);
display.add("gui", value);
display.add("ground", value);
display.add("fixed", value);

object.add("display", display);

final String key = "attachable_" + entry.getKey() + "_" + modelEntry.getKey();
final String javaModelName = StringUtil.makeIdentifierValueSafe(key);

javaContent.putString("assets/viabedrock/models/attachable/" + javaModelName + ".json", object.toString());

final int javaModelData = getCustomModelData(key);
final JsonObject override = new JsonObject();
override.addProperty("model", "viabedrock:attachable/" + javaModelName);
final JsonObject predicate = new JsonObject();
predicate.addProperty("custom_model_data", javaModelData);
override.add("predicate", predicate);

if (overridesMap.put(javaModelData, override) != null) {
throw new IllegalStateException("Duplicate custom model data: " + override);
}
}
}

if (!overridesMap.isEmpty()) {
final JsonArray overrides = new JsonArray();
overridesMap.values().forEach(overrides::add);

final JsonObject attachableDefinition = new JsonObject();
attachableDefinition.addProperty("parent", "minecraft:item/generated");
attachableDefinition.add("overrides", overrides);
final JsonObject layer0 = new JsonObject();
layer0.addProperty("layer0", "minecraft:item/" + ITEM);
attachableDefinition.add("textures", layer0);
javaContent.putJson("assets/minecraft/models/item/" + ITEM + ".json", attachableDefinition);
}
}

public static int getCustomModelData(final String key) {
return Math.abs(key.hashCode() + 1); // 0 is used for the default model
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ public class ResourcePacksStorage extends StoredObject {
private TextDefinitions texts;
private BlockDefinitions blocks;
private ItemDefinitions items;
private AttachableDefinitions attachables;
private TextureDefinitions textures;
private SoundDefinitions sounds;
private ParticleDefinitions particles;
Expand Down Expand Up @@ -149,6 +150,7 @@ public void setPackStack(final UUID[] resourcePackStack, final UUID[] behaviourP
this.texts = new TextDefinitions(this);
this.blocks = new BlockDefinitions(this);
this.items = new ItemDefinitions(this);
this.attachables = new AttachableDefinitions(this);
this.textures = new TextureDefinitions(this);
this.sounds = new SoundDefinitions(this);
this.particles = new ParticleDefinitions(this);
Expand Down Expand Up @@ -201,6 +203,10 @@ public ItemDefinitions getItems() {
return this.items;
}

public AttachableDefinitions getAttachables() {
return this.attachables;
}

public TextureDefinitions getTextures() {
return this.textures;
}
Expand Down

0 comments on commit ed85285

Please sign in to comment.