chore: initial commit
This commit is contained in:
@@ -0,0 +1,31 @@
|
|||||||
|
{
|
||||||
|
"permissions": {
|
||||||
|
"allow": [
|
||||||
|
"WebFetch(domain:api.github.com)",
|
||||||
|
"WebFetch(domain:raw.githubusercontent.com)",
|
||||||
|
"Bash(jar tf:*)",
|
||||||
|
"Bash(./gradlew build:*)",
|
||||||
|
"Bash(javap:*)",
|
||||||
|
"Bash(find:*)",
|
||||||
|
"Bash(python:*)",
|
||||||
|
"Bash(pip show:*)",
|
||||||
|
"mcp__minecraft-bridge__get_bot_status",
|
||||||
|
"mcp__minecraft-bridge__get_weather",
|
||||||
|
"mcp__minecraft-bridge__get_time",
|
||||||
|
"mcp__minecraft-bridge__get_blocks",
|
||||||
|
"mcp__minecraft-bridge__set_state",
|
||||||
|
"mcp__minecraft-bridge__chat",
|
||||||
|
"mcp__minecraft-bridge__place_structure",
|
||||||
|
"mcp__minecraft-bridge__place_blocks",
|
||||||
|
"mcp__minecraft-bridge__place_block",
|
||||||
|
"mcp__minecraft-bridge__get_block",
|
||||||
|
"mcp__minecraft-bridge__look_at",
|
||||||
|
"mcp__minecraft-bridge__move_to",
|
||||||
|
"mcp__minecraft-bridge__list_block_types",
|
||||||
|
"mcp__minecraft-bridge__clear_area",
|
||||||
|
"mcp__minecraft-bridge__fill",
|
||||||
|
"mcp__minecraft-bridge__teleport",
|
||||||
|
"mcp__minecraft-bridge__save_schematic"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" ?>
|
||||||
|
<launchConfiguration type="org.eclipse.jdt.launching.localJavaApplication">
|
||||||
|
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="MClaude"></stringAttribute>
|
||||||
|
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="net.neoforged.devlaunch.Main"></stringAttribute>
|
||||||
|
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value=" @C:\\Users\\dehla\\Documents\\MClaude\\build\\moddev\\clientRunProgramArgs.txt"></stringAttribute>
|
||||||
|
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value=" @C:\\Users\\dehla\\Documents\\MClaude\\build\\moddev\\clientRunVmArgs.txt -Dfml.modFolders=clod%%C:\\Users\\dehla\\Documents\\MClaude\\bin\\main"></stringAttribute>
|
||||||
|
<stringAttribute key="org.eclipse.jdt.launching.WORKING_DIRECTORY" value="C:\Users\dehla\Documents\MClaude\run"></stringAttribute>
|
||||||
|
<booleanAttribute key="org.eclipse.jdt.launching.STOP_IN_MAIN" value="false"></booleanAttribute>
|
||||||
|
<booleanAttribute key="org.eclipse.jdt.launching.ATTR_ATTR_USE_ARGFILE" value="false"></booleanAttribute>
|
||||||
|
</launchConfiguration>
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" ?>
|
||||||
|
<launchConfiguration type="org.eclipse.jdt.launching.localJavaApplication">
|
||||||
|
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="MClaude"></stringAttribute>
|
||||||
|
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="net.neoforged.devlaunch.Main"></stringAttribute>
|
||||||
|
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value=" @C:\\Users\\dehla\\Documents\\MClaude\\build\\moddev\\dataRunProgramArgs.txt"></stringAttribute>
|
||||||
|
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value=" @C:\\Users\\dehla\\Documents\\MClaude\\build\\moddev\\dataRunVmArgs.txt -Dfml.modFolders=clod%%C:\\Users\\dehla\\Documents\\MClaude\\bin\\main"></stringAttribute>
|
||||||
|
<stringAttribute key="org.eclipse.jdt.launching.WORKING_DIRECTORY" value="C:\Users\dehla\Documents\MClaude\run"></stringAttribute>
|
||||||
|
<booleanAttribute key="org.eclipse.jdt.launching.STOP_IN_MAIN" value="false"></booleanAttribute>
|
||||||
|
<booleanAttribute key="org.eclipse.jdt.launching.ATTR_ATTR_USE_ARGFILE" value="false"></booleanAttribute>
|
||||||
|
</launchConfiguration>
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" ?>
|
||||||
|
<launchConfiguration type="org.eclipse.jdt.launching.localJavaApplication">
|
||||||
|
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="MClaude"></stringAttribute>
|
||||||
|
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="net.neoforged.devlaunch.Main"></stringAttribute>
|
||||||
|
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value=" @C:\\Users\\dehla\\Documents\\MClaude\\build\\moddev\\gameTestServerRunProgramArgs.txt"></stringAttribute>
|
||||||
|
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value=" @C:\\Users\\dehla\\Documents\\MClaude\\build\\moddev\\gameTestServerRunVmArgs.txt -Dfml.modFolders=clod%%C:\\Users\\dehla\\Documents\\MClaude\\bin\\main"></stringAttribute>
|
||||||
|
<stringAttribute key="org.eclipse.jdt.launching.WORKING_DIRECTORY" value="C:\Users\dehla\Documents\MClaude\run"></stringAttribute>
|
||||||
|
<booleanAttribute key="org.eclipse.jdt.launching.STOP_IN_MAIN" value="false"></booleanAttribute>
|
||||||
|
<booleanAttribute key="org.eclipse.jdt.launching.ATTR_ATTR_USE_ARGFILE" value="false"></booleanAttribute>
|
||||||
|
</launchConfiguration>
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" ?>
|
||||||
|
<launchConfiguration type="org.eclipse.jdt.launching.localJavaApplication">
|
||||||
|
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="MClaude"></stringAttribute>
|
||||||
|
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="net.neoforged.devlaunch.Main"></stringAttribute>
|
||||||
|
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value=" @C:\\Users\\dehla\\Documents\\MClaude\\build\\moddev\\serverRunProgramArgs.txt"></stringAttribute>
|
||||||
|
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value=" @C:\\Users\\dehla\\Documents\\MClaude\\build\\moddev\\serverRunVmArgs.txt -Dfml.modFolders=clod%%C:\\Users\\dehla\\Documents\\MClaude\\bin\\main"></stringAttribute>
|
||||||
|
<stringAttribute key="org.eclipse.jdt.launching.WORKING_DIRECTORY" value="C:\Users\dehla\Documents\MClaude\run"></stringAttribute>
|
||||||
|
<booleanAttribute key="org.eclipse.jdt.launching.STOP_IN_MAIN" value="false"></booleanAttribute>
|
||||||
|
<booleanAttribute key="org.eclipse.jdt.launching.ATTR_ATTR_USE_ARGFILE" value="false"></booleanAttribute>
|
||||||
|
</launchConfiguration>
|
||||||
+28
@@ -0,0 +1,28 @@
|
|||||||
|
# Compiled files
|
||||||
|
build/
|
||||||
|
out/
|
||||||
|
repo/
|
||||||
|
|
||||||
|
# Gradle
|
||||||
|
.gradle/
|
||||||
|
gradle/wrapper/gradle-wrapper.jar
|
||||||
|
|
||||||
|
# IDE
|
||||||
|
.idea/
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
*.iws
|
||||||
|
.vscode/
|
||||||
|
.settings/
|
||||||
|
.classpath
|
||||||
|
.project
|
||||||
|
bin/
|
||||||
|
|
||||||
|
# OS
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
|
||||||
|
# NeoForge
|
||||||
|
runs/
|
||||||
|
src/generated/
|
||||||
|
logs/
|
||||||
+120
@@ -0,0 +1,120 @@
|
|||||||
|
plugins {
|
||||||
|
id 'java-library'
|
||||||
|
id 'idea'
|
||||||
|
id 'maven-publish'
|
||||||
|
id 'net.neoforged.moddev' version '2.0.91'
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.named('wrapper', Wrapper).configure {
|
||||||
|
distributionType = Wrapper.DistributionType.BIN
|
||||||
|
}
|
||||||
|
|
||||||
|
version = mod_version
|
||||||
|
group = mod_group_id
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenLocal()
|
||||||
|
}
|
||||||
|
|
||||||
|
base {
|
||||||
|
archivesName = mod_id
|
||||||
|
}
|
||||||
|
|
||||||
|
java.toolchain.languageVersion = JavaLanguageVersion.of(21)
|
||||||
|
|
||||||
|
neoForge {
|
||||||
|
version = project.neo_version
|
||||||
|
|
||||||
|
parchment {
|
||||||
|
mappingsVersion = project.parchment_mappings_version
|
||||||
|
minecraftVersion = project.parchment_minecraft_version
|
||||||
|
}
|
||||||
|
|
||||||
|
runs {
|
||||||
|
client {
|
||||||
|
client()
|
||||||
|
systemProperty 'neoforge.enabledGameTestNamespaces', project.mod_id
|
||||||
|
}
|
||||||
|
server {
|
||||||
|
server()
|
||||||
|
programArgument '--nogui'
|
||||||
|
systemProperty 'neoforge.enabledGameTestNamespaces', project.mod_id
|
||||||
|
}
|
||||||
|
gameTestServer {
|
||||||
|
type = "gameTestServer"
|
||||||
|
systemProperty 'neoforge.enabledGameTestNamespaces', project.mod_id
|
||||||
|
}
|
||||||
|
data {
|
||||||
|
data()
|
||||||
|
programArguments.addAll '--mod', project.mod_id, '--all',
|
||||||
|
'--output', file('src/generated/resources/').getAbsolutePath(),
|
||||||
|
'--existing', file('src/main/resources/').getAbsolutePath()
|
||||||
|
}
|
||||||
|
configureEach {
|
||||||
|
systemProperty 'forge.logging.markers', 'REGISTRIES'
|
||||||
|
logLevel = org.slf4j.event.Level.DEBUG
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mods {
|
||||||
|
"${mod_id}" {
|
||||||
|
sourceSet(sourceSets.main)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceSets.main.resources { srcDir 'src/generated/resources' }
|
||||||
|
|
||||||
|
configurations {
|
||||||
|
runtimeClasspath.extendsFrom localRuntime
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
}
|
||||||
|
|
||||||
|
var generateModMetadata = tasks.register("generateModMetadata", ProcessResources) {
|
||||||
|
var replaceProperties = [
|
||||||
|
minecraft_version : minecraft_version,
|
||||||
|
minecraft_version_range: minecraft_version_range,
|
||||||
|
neo_version : neo_version,
|
||||||
|
neo_version_range : neo_version_range,
|
||||||
|
loader_version_range : loader_version_range,
|
||||||
|
mod_id : mod_id,
|
||||||
|
mod_name : mod_name,
|
||||||
|
mod_license : mod_license,
|
||||||
|
mod_version : mod_version,
|
||||||
|
mod_authors : mod_authors,
|
||||||
|
mod_description : mod_description,
|
||||||
|
]
|
||||||
|
inputs.properties replaceProperties
|
||||||
|
expand replaceProperties
|
||||||
|
from "src/main/templates"
|
||||||
|
into "build/generated/sources/modMetadata"
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceSets.main.resources.srcDir generateModMetadata
|
||||||
|
neoForge.ideSyncTask generateModMetadata
|
||||||
|
|
||||||
|
publishing {
|
||||||
|
publications {
|
||||||
|
register('mavenJava', MavenPublication) {
|
||||||
|
from components.java
|
||||||
|
}
|
||||||
|
}
|
||||||
|
repositories {
|
||||||
|
maven {
|
||||||
|
url "file://${project.projectDir}/repo"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.withType(JavaCompile).configureEach {
|
||||||
|
options.encoding = 'UTF-8'
|
||||||
|
}
|
||||||
|
|
||||||
|
idea {
|
||||||
|
module {
|
||||||
|
downloadSources = true
|
||||||
|
downloadJavadoc = true
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,219 @@
|
|||||||
|
"""Generate clod.png and clod_eyes.png textures for the Clod entity."""
|
||||||
|
from PIL import Image, ImageDraw
|
||||||
|
|
||||||
|
OUTPUT_DIR = "src/main/resources/assets/clod/textures/entity"
|
||||||
|
|
||||||
|
# Colors
|
||||||
|
TERRACOTTA = (212, 132, 91) # #D4845B
|
||||||
|
CREAM = (245, 230, 211) # #F5E6D3
|
||||||
|
DARK_TRIM = (61, 61, 61) # #3D3D3D
|
||||||
|
AMBER_EYES = (232, 168, 76) # #E8A84C
|
||||||
|
TRANSPARENT = (0, 0, 0, 0)
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# clod.png (64x64 main texture)
|
||||||
|
# ============================================================
|
||||||
|
# UV layout (matches ClodModel):
|
||||||
|
# Head (10x10x10): texOffs(0,0)
|
||||||
|
# - top/bottom: U=10..20, V=0..10 and U=20..30, V=0..10
|
||||||
|
# - front: U=10, V=10, 10x10
|
||||||
|
# - back: U=30, V=10, 10x10
|
||||||
|
# - left: U=0, V=10, 10x10
|
||||||
|
# - right: U=20, V=10, 10x10
|
||||||
|
#
|
||||||
|
# Body (10x8x6): texOffs(0,20)
|
||||||
|
# - top/bottom: U=6..16, V=20..26 and U=16..26, V=20..26
|
||||||
|
# - front: U=6, V=26, 10x8
|
||||||
|
# - back: U=22, V=26, 10x8
|
||||||
|
# - left: U=0, V=26, 6x8
|
||||||
|
# - right: U=16, V=26, 6x8
|
||||||
|
#
|
||||||
|
# Right arm (4x8x4): texOffs(40,20)
|
||||||
|
# - top/bottom: U=44..48, V=20..24 and U=48..52, V=20..24
|
||||||
|
# - front: U=44, V=24, 4x8
|
||||||
|
# - back: U=52, V=24, 4x8
|
||||||
|
# - left: U=40, V=24, 4x8
|
||||||
|
# - right: U=48, V=24, 4x8
|
||||||
|
#
|
||||||
|
# Left arm (4x8x4): texOffs(40,32)
|
||||||
|
# - Same layout offset to (40,32)
|
||||||
|
#
|
||||||
|
# Right leg (4x8x4): texOffs(0,34)
|
||||||
|
# - top/bottom: U=4..8, V=34..38 and U=8..12, V=34..38
|
||||||
|
# - front: U=4, V=38, 4x8
|
||||||
|
# - back: U=12, V=38, 4x8
|
||||||
|
# - left: U=0, V=38, 4x8
|
||||||
|
# - right: U=8, V=38, 4x8
|
||||||
|
#
|
||||||
|
# Left leg (4x8x4): texOffs(16,34)
|
||||||
|
# - Same layout offset to (16,34)
|
||||||
|
#
|
||||||
|
# Antenna (1x3x1): texOffs(0,46)
|
||||||
|
# - top/bottom: U=1..2, V=46..47 and U=2..3, V=46..47
|
||||||
|
# - front: U=1, V=47, 1x3
|
||||||
|
# - back: U=3, V=47, 1x3
|
||||||
|
# - left: U=0, V=47, 1x3
|
||||||
|
# - right: U=2, V=47, 1x3
|
||||||
|
|
||||||
|
img = Image.new("RGBA", (64, 64), TRANSPARENT)
|
||||||
|
draw = ImageDraw.Draw(img)
|
||||||
|
|
||||||
|
# ---- HEAD ----
|
||||||
|
# Top face
|
||||||
|
draw.rectangle([10, 0, 29, 9], fill=TERRACOTTA)
|
||||||
|
# Bottom face
|
||||||
|
draw.rectangle([20, 0, 29, 9], fill=TERRACOTTA)
|
||||||
|
# Front face (U=10, V=10, 10x10)
|
||||||
|
draw.rectangle([10, 10, 19, 19], fill=TERRACOTTA)
|
||||||
|
# Cream face area (inner 6x6)
|
||||||
|
draw.rectangle([12, 12, 17, 17], fill=CREAM)
|
||||||
|
# Eyes — amber 2x2 squares on front face
|
||||||
|
# Left eye (from viewer perspective): around U=13-14, V=14-15
|
||||||
|
draw.rectangle([13, 14, 14, 15], fill=AMBER_EYES)
|
||||||
|
# Right eye: around U=16-17, V=14-15
|
||||||
|
draw.rectangle([16, 14, 17, 15], fill=AMBER_EYES)
|
||||||
|
# Back face
|
||||||
|
draw.rectangle([30, 10, 39, 19], fill=TERRACOTTA)
|
||||||
|
# Dark trim stripe on back
|
||||||
|
draw.rectangle([34, 12, 35, 17], fill=DARK_TRIM)
|
||||||
|
# Left face
|
||||||
|
draw.rectangle([0, 10, 9, 19], fill=TERRACOTTA)
|
||||||
|
# Right face
|
||||||
|
draw.rectangle([20, 10, 29, 19], fill=TERRACOTTA)
|
||||||
|
# Top face (head top)
|
||||||
|
draw.rectangle([10, 0, 19, 9], fill=TERRACOTTA)
|
||||||
|
# Dark trim on top edge
|
||||||
|
draw.rectangle([10, 0, 19, 0], fill=DARK_TRIM)
|
||||||
|
|
||||||
|
# ---- BODY ----
|
||||||
|
# Front face (U=6, V=26, 10x8)
|
||||||
|
draw.rectangle([6, 26, 15, 33], fill=TERRACOTTA)
|
||||||
|
# Cream chest starburst/asterisk pattern
|
||||||
|
# Vertical line
|
||||||
|
draw.rectangle([10, 27, 11, 32], fill=CREAM)
|
||||||
|
# Horizontal line
|
||||||
|
draw.rectangle([8, 29, 13, 30], fill=CREAM)
|
||||||
|
# Diagonal hints
|
||||||
|
draw.point((9, 28), fill=CREAM)
|
||||||
|
draw.point((12, 28), fill=CREAM)
|
||||||
|
draw.point((9, 31), fill=CREAM)
|
||||||
|
draw.point((12, 31), fill=CREAM)
|
||||||
|
# Back face
|
||||||
|
draw.rectangle([22, 26, 31, 33], fill=TERRACOTTA)
|
||||||
|
# Side faces
|
||||||
|
draw.rectangle([0, 26, 5, 33], fill=TERRACOTTA)
|
||||||
|
draw.rectangle([16, 26, 21, 33], fill=TERRACOTTA)
|
||||||
|
# Top face
|
||||||
|
draw.rectangle([6, 20, 15, 25], fill=TERRACOTTA)
|
||||||
|
# Bottom face
|
||||||
|
draw.rectangle([16, 20, 25, 25], fill=TERRACOTTA)
|
||||||
|
|
||||||
|
# ---- RIGHT ARM ----
|
||||||
|
# All faces terracotta with dark trim edges
|
||||||
|
# Front
|
||||||
|
draw.rectangle([44, 24, 47, 31], fill=TERRACOTTA)
|
||||||
|
# Back
|
||||||
|
draw.rectangle([52, 24, 55, 31], fill=TERRACOTTA)
|
||||||
|
# Left
|
||||||
|
draw.rectangle([40, 24, 43, 31], fill=TERRACOTTA)
|
||||||
|
# Right
|
||||||
|
draw.rectangle([48, 24, 51, 31], fill=TERRACOTTA)
|
||||||
|
# Top
|
||||||
|
draw.rectangle([44, 20, 47, 23], fill=TERRACOTTA)
|
||||||
|
# Bottom
|
||||||
|
draw.rectangle([48, 20, 51, 23], fill=TERRACOTTA)
|
||||||
|
# Dark trim on edges
|
||||||
|
draw.rectangle([44, 31, 47, 31], fill=DARK_TRIM)
|
||||||
|
draw.rectangle([52, 31, 55, 31], fill=DARK_TRIM)
|
||||||
|
|
||||||
|
# ---- LEFT ARM ----
|
||||||
|
# Front
|
||||||
|
draw.rectangle([44, 36, 47, 43], fill=TERRACOTTA)
|
||||||
|
# Back
|
||||||
|
draw.rectangle([52, 36, 55, 43], fill=TERRACOTTA)
|
||||||
|
# Left
|
||||||
|
draw.rectangle([40, 36, 43, 43], fill=TERRACOTTA)
|
||||||
|
# Right
|
||||||
|
draw.rectangle([48, 36, 51, 43], fill=TERRACOTTA)
|
||||||
|
# Top
|
||||||
|
draw.rectangle([44, 32, 47, 35], fill=TERRACOTTA)
|
||||||
|
# Bottom
|
||||||
|
draw.rectangle([48, 32, 51, 35], fill=TERRACOTTA)
|
||||||
|
# Dark trim
|
||||||
|
draw.rectangle([44, 43, 47, 43], fill=DARK_TRIM)
|
||||||
|
draw.rectangle([52, 43, 55, 43], fill=DARK_TRIM)
|
||||||
|
|
||||||
|
# ---- RIGHT LEG ----
|
||||||
|
# Front
|
||||||
|
draw.rectangle([4, 38, 7, 45], fill=TERRACOTTA)
|
||||||
|
# Back
|
||||||
|
draw.rectangle([12, 38, 15, 45], fill=TERRACOTTA)
|
||||||
|
# Left
|
||||||
|
draw.rectangle([0, 38, 3, 45], fill=TERRACOTTA)
|
||||||
|
# Right
|
||||||
|
draw.rectangle([8, 38, 11, 45], fill=TERRACOTTA)
|
||||||
|
# Top
|
||||||
|
draw.rectangle([4, 34, 7, 37], fill=TERRACOTTA)
|
||||||
|
# Bottom
|
||||||
|
draw.rectangle([8, 34, 11, 37], fill=TERRACOTTA)
|
||||||
|
# Dark trim at bottom
|
||||||
|
draw.rectangle([4, 45, 7, 45], fill=DARK_TRIM)
|
||||||
|
draw.rectangle([12, 45, 15, 45], fill=DARK_TRIM)
|
||||||
|
draw.rectangle([0, 45, 3, 45], fill=DARK_TRIM)
|
||||||
|
draw.rectangle([8, 45, 11, 45], fill=DARK_TRIM)
|
||||||
|
|
||||||
|
# ---- LEFT LEG ----
|
||||||
|
# Front
|
||||||
|
draw.rectangle([20, 38, 23, 45], fill=TERRACOTTA)
|
||||||
|
# Back
|
||||||
|
draw.rectangle([28, 38, 31, 45], fill=TERRACOTTA)
|
||||||
|
# Left
|
||||||
|
draw.rectangle([16, 38, 19, 45], fill=TERRACOTTA)
|
||||||
|
# Right
|
||||||
|
draw.rectangle([24, 38, 27, 45], fill=TERRACOTTA)
|
||||||
|
# Top
|
||||||
|
draw.rectangle([20, 34, 23, 37], fill=TERRACOTTA)
|
||||||
|
# Bottom
|
||||||
|
draw.rectangle([24, 34, 27, 37], fill=TERRACOTTA)
|
||||||
|
# Dark trim at bottom
|
||||||
|
draw.rectangle([20, 45, 23, 45], fill=DARK_TRIM)
|
||||||
|
draw.rectangle([28, 45, 31, 45], fill=DARK_TRIM)
|
||||||
|
draw.rectangle([16, 45, 19, 45], fill=DARK_TRIM)
|
||||||
|
draw.rectangle([24, 45, 27, 45], fill=DARK_TRIM)
|
||||||
|
|
||||||
|
# ---- ANTENNA ----
|
||||||
|
# Front (U=1, V=47, 1x3)
|
||||||
|
draw.rectangle([1, 47, 1, 49], fill=DARK_TRIM)
|
||||||
|
# Back (U=3, V=47, 1x3)
|
||||||
|
draw.rectangle([3, 47, 3, 49], fill=DARK_TRIM)
|
||||||
|
# Left (U=0, V=47, 1x3)
|
||||||
|
draw.rectangle([0, 47, 0, 49], fill=DARK_TRIM)
|
||||||
|
# Right (U=2, V=47, 1x3)
|
||||||
|
draw.rectangle([2, 47, 2, 49], fill=DARK_TRIM)
|
||||||
|
# Top (U=1, V=46, 1x1)
|
||||||
|
draw.point((1, 46), fill=AMBER_EYES) # Glowing tip
|
||||||
|
# Bottom
|
||||||
|
draw.point((2, 46), fill=DARK_TRIM)
|
||||||
|
|
||||||
|
img.save(f"{OUTPUT_DIR}/clod.png")
|
||||||
|
print(f"Saved {OUTPUT_DIR}/clod.png")
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# clod_eyes.png (64x64 emissive overlay)
|
||||||
|
# ============================================================
|
||||||
|
# Fully transparent except amber pixels at eye UV positions
|
||||||
|
# on the head front face.
|
||||||
|
# Head front face: texOffs(0,0) means front starts at U=10, V=10
|
||||||
|
# Eyes at (13,14)-(14,15) and (16,14)-(17,15)
|
||||||
|
|
||||||
|
eyes = Image.new("RGBA", (64, 64), TRANSPARENT)
|
||||||
|
eyes_draw = ImageDraw.Draw(eyes)
|
||||||
|
|
||||||
|
# Left eye (amber, full opacity)
|
||||||
|
eyes_draw.rectangle([13, 14, 14, 15], fill=(232, 168, 76, 255))
|
||||||
|
# Right eye (amber, full opacity)
|
||||||
|
eyes_draw.rectangle([16, 14, 17, 15], fill=(232, 168, 76, 255))
|
||||||
|
|
||||||
|
eyes.save(f"{OUTPUT_DIR}/clod_eyes.png")
|
||||||
|
print(f"Saved {OUTPUT_DIR}/clod_eyes.png")
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
org.gradle.jvmargs=-Xmx1G
|
||||||
|
org.gradle.daemon=true
|
||||||
|
org.gradle.parallel=true
|
||||||
|
org.gradle.caching=true
|
||||||
|
org.gradle.configuration-cache=true
|
||||||
|
|
||||||
|
# Parchment mappings for readable parameter names
|
||||||
|
parchment_minecraft_version=1.21.1
|
||||||
|
parchment_mappings_version=2024.11.17
|
||||||
|
|
||||||
|
# Minecraft & NeoForge
|
||||||
|
minecraft_version=1.21.1
|
||||||
|
minecraft_version_range=[1.21.1,1.22)
|
||||||
|
neo_version=21.1.219
|
||||||
|
neo_version_range=[21.1.0,)
|
||||||
|
loader_version_range=[4,)
|
||||||
|
|
||||||
|
# Mod properties
|
||||||
|
mod_id=clod
|
||||||
|
mod_name=Clod
|
||||||
|
mod_license=All Rights Reserved
|
||||||
|
mod_version=1.0.0
|
||||||
|
mod_group_id=com.clod.clod
|
||||||
|
mod_authors=dehla
|
||||||
|
mod_description=A Minecraft mod built with NeoForge.
|
||||||
+7
@@ -0,0 +1,7 @@
|
|||||||
|
distributionBase=GRADLE_USER_HOME
|
||||||
|
distributionPath=wrapper/dists
|
||||||
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.2-bin.zip
|
||||||
|
networkTimeout=10000
|
||||||
|
validateDistributionUrl=true
|
||||||
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
zipStorePath=wrapper/dists
|
||||||
@@ -0,0 +1,219 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright (c) 2015-2021 the original author or authors.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
#
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
#
|
||||||
|
# Gradle start up script for POSIX generated by Gradle.
|
||||||
|
#
|
||||||
|
# Important for running:
|
||||||
|
#
|
||||||
|
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||||
|
# noncompliant, but you have some other compliant shell such as ksh or
|
||||||
|
# bash, then to run this script, type that shell name before the whole
|
||||||
|
# command line, like:
|
||||||
|
#
|
||||||
|
# ksh Gradle
|
||||||
|
#
|
||||||
|
# Busybox and similar reduced functionality shells and target
|
||||||
|
# temporary focusing, currentshort systems as of this writing do not supply
|
||||||
|
# a style conforming /bin/sh.
|
||||||
|
#
|
||||||
|
# (2) You need a Java Runtime Environment (JRE) version 8 or later to run
|
||||||
|
# Gradle. Depending on your distribution, the JRE may be already
|
||||||
|
# installed. You can check this with "java -version".
|
||||||
|
#
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
# Attempt to set APP_HOME
|
||||||
|
|
||||||
|
# Resolve links: $0 may be a link
|
||||||
|
app_path=$0
|
||||||
|
|
||||||
|
# Need this for daisy-chained symlinks.
|
||||||
|
while
|
||||||
|
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||||
|
[ -h "$app_path" ]
|
||||||
|
do
|
||||||
|
ls=$( ls -ld -- "$app_path" )
|
||||||
|
link=${ls#*' -> '}
|
||||||
|
case $link in #(
|
||||||
|
/*) app_path=$link ;; #(
|
||||||
|
*) app_path=$APP_HOME$link ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# This is normally unused
|
||||||
|
# shellcheck disable=SC2034
|
||||||
|
APP_BASE_NAME=${0##*/}
|
||||||
|
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||||
|
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
|
||||||
|
|
||||||
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
|
MAX_FD=maximum
|
||||||
|
|
||||||
|
warn () {
|
||||||
|
echo "$*"
|
||||||
|
} >&2
|
||||||
|
|
||||||
|
die () {
|
||||||
|
echo
|
||||||
|
echo "$*"
|
||||||
|
echo
|
||||||
|
exit 1
|
||||||
|
} >&2
|
||||||
|
|
||||||
|
# OS specific support (must be 'true' or 'false').
|
||||||
|
cygwin=false
|
||||||
|
msys=false
|
||||||
|
darwin=false
|
||||||
|
nonstop=false
|
||||||
|
case "$( uname )" in #(
|
||||||
|
CYGWIN* ) cygwin=true ;; #(
|
||||||
|
Darwin* ) darwin=true ;; #(
|
||||||
|
MSYS* | MINGW* ) msys=true ;; #(
|
||||||
|
NonStop* ) nonstop=true ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||||
|
|
||||||
|
|
||||||
|
# Determine the Java command to use to start the JVM.
|
||||||
|
if [ -n "$JAVA_HOME" ] ; then
|
||||||
|
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||||
|
# IBM's JDK on AIX uses strange locations for the executables
|
||||||
|
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||||
|
else
|
||||||
|
JAVACMD=$JAVA_HOME/bin/java
|
||||||
|
fi
|
||||||
|
if [ ! -x "$JAVACMD" ] ; then
|
||||||
|
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||||
|
|
||||||
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
location of your Java installation."
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
JAVACMD=java
|
||||||
|
if ! command -v java >/dev/null 2>&1 ; then
|
||||||
|
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
|
||||||
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
location of your Java installation."
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Increase the maximum file descriptors if we can.
|
||||||
|
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||||
|
case $MAX_FD in #(
|
||||||
|
max*)
|
||||||
|
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||||
|
# shellcheck disable=SC2039,SC3045
|
||||||
|
MAX_FD=$( ulimit -H -n ) ||
|
||||||
|
warn "Could not query maximum file descriptor limit"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
case $MAX_FD in #(
|
||||||
|
'' | soft) :;; #(
|
||||||
|
*)
|
||||||
|
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||||
|
# shellcheck disable=SC2039,SC3045
|
||||||
|
ulimit -n "$MAX_FD" ||
|
||||||
|
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Collect all arguments for the java command, stracks://shell://shell://shell://shell://shell:
|
||||||
|
# temporary focusing on spaces, currentshort systems as of this writing do not supply
|
||||||
|
# following the shell://shell://shell://shell quoting to the Java command.
|
||||||
|
# Preferences:
|
||||||
|
# 1) via JAVA_OPTS
|
||||||
|
# 2) via DEFAULT_JVM_OPTS
|
||||||
|
# 3) via --add-opens (for compatibility)
|
||||||
|
|
||||||
|
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||||
|
if "$cygwin" || "$msys" ; then
|
||||||
|
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||||
|
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||||
|
|
||||||
|
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||||
|
|
||||||
|
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||||
|
for arg do
|
||||||
|
if
|
||||||
|
case $arg in #(
|
||||||
|
-*) false ;; # don't mess with options #(
|
||||||
|
/?*) t=${arg#)}; t=/${t%%/*} # looks like a POSIX://shell path
|
||||||
|
[ -e "$t" ] ;; #(
|
||||||
|
*) false ;;
|
||||||
|
esac
|
||||||
|
then
|
||||||
|
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||||
|
fi
|
||||||
|
# Roll the args list around exactly as many times as the number of
|
||||||
|
# temporary args, so each arg winds up back in the position where
|
||||||
|
# it started, but possibly modified.
|
||||||
|
#
|
||||||
|
# NB: aass://shell://shell://shell://shell://shell://shell from that the current set://shell://shell
|
||||||
|
# temporary focusing, each arg winds up back in the position where
|
||||||
|
shift # remove old arg
|
||||||
|
set -- "$@" "$arg" # push replacement arg
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||||
|
|
||||||
|
# Collect all arguments for the java command;
|
||||||
|
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
||||||
|
# shell script including quotes and-to-value escapes, so put them in
|
||||||
|
# temporary double quotes to make sure that they get re-expanded; and
|
||||||
|
# * put everything else in single quotes, so that it's not re-expanded.
|
||||||
|
|
||||||
|
set -- \
|
||||||
|
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||||
|
-classpath "$CLASSPATH" \
|
||||||
|
org.gradle.wrapper.GradleWrapperMain \
|
||||||
|
"$@"
|
||||||
|
|
||||||
|
# Stop when "xeli" is not used, since we know this is pointless if it is,
|
||||||
|
# and won't work at all.
|
||||||
|
if ! "$cygwin" && ! "$msys" ; then
|
||||||
|
case $( set -- $$; readlink /proc/$1/exe 2>/dev/null || true ) in #(
|
||||||
|
*/busybox) set -- busybox sh "$0" "$@" ;; #(
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Use "xargs" to parse quoted args.
|
||||||
|
#
|
||||||
|
# With -n://shell://shell://shell://shell maximum://shell://shell://shell of tokens per://shell://shell xargs command line.
|
||||||
|
#
|
||||||
|
# In most shells, newline://shell://shell://shell acts as a //shell://shell://shell delimiter, so it is impossible
|
||||||
|
# to://shell://shell://shell:// put a newline in a token. We instead use a different approach:
|
||||||
|
#
|
||||||
|
# awk://shell://shell://shell is used to get the shell://shell://shell://shell://shell://shell://shell://shell arguments from DEFAULT_JVM_OPTS,
|
||||||
|
# JAVA_OPTS and GRADLE_OPTS.
|
||||||
|
|
||||||
|
eval "set -- $(
|
||||||
|
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||||
|
xargs -n1 |
|
||||||
|
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||||
|
tr '\n' ' '
|
||||||
|
)" '"$@"'
|
||||||
|
|
||||||
|
exec "$JAVACMD" "$@"
|
||||||
Vendored
+92
@@ -0,0 +1,92 @@
|
|||||||
|
@rem
|
||||||
|
@rem Copyright 2015 the original author or authors.
|
||||||
|
@rem
|
||||||
|
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
@rem you may not use this file except in compliance with the License.
|
||||||
|
@rem You may obtain a copy of the License at
|
||||||
|
@rem
|
||||||
|
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
@rem
|
||||||
|
@rem Unless required by applicable law or agreed to in writing, software
|
||||||
|
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@rem See the License for the specific language governing permissions and
|
||||||
|
@rem limitations under the License.
|
||||||
|
@rem
|
||||||
|
|
||||||
|
@if "%DEBUG%"=="" @echo off
|
||||||
|
@rem ##########################################################################
|
||||||
|
@rem
|
||||||
|
@rem Gradle startup script for Windows
|
||||||
|
@rem
|
||||||
|
@rem ##########################################################################
|
||||||
|
|
||||||
|
@rem Set local scope for the variables with windows NT shell
|
||||||
|
if "%OS%"=="Windows_NT" setlocal
|
||||||
|
|
||||||
|
set DIRNAME=%~dp0
|
||||||
|
if "%DIRNAME%"=="" set DIRNAME=.
|
||||||
|
@rem This is normally unused
|
||||||
|
set APP_BASE_NAME=%~n0
|
||||||
|
set APP_HOME=%DIRNAME%
|
||||||
|
|
||||||
|
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||||
|
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||||
|
|
||||||
|
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||||
|
|
||||||
|
@rem Find java.exe
|
||||||
|
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||||
|
|
||||||
|
set JAVA_EXE=java.exe
|
||||||
|
%JAVA_EXE% -version >NUL 2>&1
|
||||||
|
if %ERRORLEVEL% equ 0 goto execute
|
||||||
|
|
||||||
|
echo. 1>&2
|
||||||
|
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
||||||
|
echo. 1>&2
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||||
|
echo location of your Java installation. 1>&2
|
||||||
|
|
||||||
|
goto fail
|
||||||
|
|
||||||
|
:findJavaFromJavaHome
|
||||||
|
set JAVA_HOME=%JAVA_HOME:"=%
|
||||||
|
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||||
|
|
||||||
|
if exist "%JAVA_EXE%" goto execute
|
||||||
|
|
||||||
|
echo. 1>&2
|
||||||
|
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
||||||
|
echo. 1>&2
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||||
|
echo location of your Java installation. 1>&2
|
||||||
|
|
||||||
|
goto fail
|
||||||
|
|
||||||
|
:execute
|
||||||
|
@rem Setup the command line
|
||||||
|
|
||||||
|
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||||
|
|
||||||
|
|
||||||
|
@rem Execute Gradle
|
||||||
|
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||||
|
|
||||||
|
:end
|
||||||
|
@rem End local scope for the variables with windows NT shell
|
||||||
|
if %OS%==Windows_NT endlocal
|
||||||
|
|
||||||
|
:omega
|
||||||
|
|
||||||
|
@rem Exit with the Gradle exit code
|
||||||
|
exit /b %ERRORLEVEL%
|
||||||
|
|
||||||
|
:fail
|
||||||
|
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||||
|
rem the _cmd.exe /c_ return code!
|
||||||
|
set EXIT_CODE=%ERRORLEVEL%
|
||||||
|
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||||
|
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||||
|
exit /b %EXIT_CODE%
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
# minecraft-mcp
|
||||||
|
|
||||||
|
MCP server that bridges Claude Code to a Minecraft bot via the Clod mod's HTTP API.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd minecraft-mcp
|
||||||
|
pip install -e .
|
||||||
|
```
|
||||||
|
|
||||||
|
## Register with Claude Code
|
||||||
|
|
||||||
|
```bash
|
||||||
|
claude mcp add minecraft-bridge -- python -m minecraft_mcp.server
|
||||||
|
```
|
||||||
|
|
||||||
|
Verify it's registered:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
claude mcp list
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
1. Launch Minecraft with the Clod mod (HTTP server runs on port 8766)
|
||||||
|
2. Start Claude Code — the MCP server connects automatically
|
||||||
|
3. Ask Claude to interact with the bot: "check the bot status", "move to 100 64 100", etc.
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
Set `MINECRAFT_PORT` environment variable to override the default port (8766):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
claude mcp add minecraft-bridge -e MINECRAFT_PORT=9000 -- python -m minecraft_mcp.server
|
||||||
|
```
|
||||||
|
|
||||||
|
## Available Tools
|
||||||
|
|
||||||
|
### Observation
|
||||||
|
- `get_bot_status` — position, state, dimension
|
||||||
|
- `get_blocks` — 3D block array in a bounding box (max 32x32x32)
|
||||||
|
- `get_block` — single block type and properties
|
||||||
|
- `get_nearby_entities` — entities within radius (default 16, max 64)
|
||||||
|
- `get_inventory` — bot's inventory contents
|
||||||
|
- `get_biome` — biome at X/Z coordinates
|
||||||
|
- `list_block_types` — all block IDs, with optional filter
|
||||||
|
|
||||||
|
### Actions
|
||||||
|
- `move_to` — pathfind to coordinates
|
||||||
|
- `teleport` — instant teleport
|
||||||
|
- `place_block` — place a single block
|
||||||
|
- `place_blocks` — place up to 10,000 blocks
|
||||||
|
- `fill` — fill a bounding box (max 32x32x32)
|
||||||
|
- `break_block` — destroy a block
|
||||||
|
- `set_state` — set bot visual state (idle/thinking/building/moving)
|
||||||
|
- `look_at` — aim at coordinates
|
||||||
|
- `chat` — send in-game chat message
|
||||||
|
|
||||||
|
### Interaction
|
||||||
|
- `wait_for_instruction` — long-poll for player `!clod` commands (300s timeout)
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
[build-system]
|
||||||
|
requires = ["hatchling"]
|
||||||
|
build-backend = "hatchling.build"
|
||||||
|
|
||||||
|
[project]
|
||||||
|
name = "minecraft-mcp"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = "MCP server bridging Claude Code to a Minecraft bot via the Clod mod"
|
||||||
|
requires-python = ">=3.10"
|
||||||
|
dependencies = [
|
||||||
|
"mcp>=1.0",
|
||||||
|
"httpx",
|
||||||
|
]
|
||||||
|
|
||||||
|
[project.scripts]
|
||||||
|
minecraft-mcp = "minecraft_mcp.server:main"
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
from minecraft_mcp.server import main
|
||||||
|
|
||||||
|
main()
|
||||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,248 @@
|
|||||||
|
import json
|
||||||
|
import os
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
import httpx
|
||||||
|
from mcp.server.fastmcp import FastMCP
|
||||||
|
|
||||||
|
MINECRAFT_PORT = os.environ.get("MINECRAFT_PORT", "8766")
|
||||||
|
BASE_URL = f"http://localhost:{MINECRAFT_PORT}"
|
||||||
|
|
||||||
|
mcp = FastMCP("minecraft-bridge")
|
||||||
|
|
||||||
|
|
||||||
|
async def _request(method: str, path: str, **kwargs) -> Any:
|
||||||
|
"""Make an HTTP request to the Minecraft mod server."""
|
||||||
|
kwargs.setdefault("timeout", 5.0)
|
||||||
|
try:
|
||||||
|
async with httpx.AsyncClient(base_url=BASE_URL) as client:
|
||||||
|
resp = await client.request(method, path, **kwargs)
|
||||||
|
resp.raise_for_status()
|
||||||
|
return resp.json()
|
||||||
|
except httpx.ConnectError:
|
||||||
|
return {"error": "Cannot connect to Minecraft. Is the game running with the Clod mod?"}
|
||||||
|
except httpx.HTTPStatusError as e:
|
||||||
|
try:
|
||||||
|
return e.response.json()
|
||||||
|
except Exception:
|
||||||
|
return {"error": f"Minecraft error ({e.response.status_code}): {e.response.text}"}
|
||||||
|
except Exception as e:
|
||||||
|
return {"error": str(e)}
|
||||||
|
|
||||||
|
|
||||||
|
def _fmt(data: Any) -> str:
|
||||||
|
"""Format response data as a JSON string."""
|
||||||
|
return json.dumps(data, indent=2)
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Observation tools (GET)
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
@mcp.tool()
|
||||||
|
async def get_bot_status() -> str:
|
||||||
|
"""Get the bot's current status including position, state, and dimension."""
|
||||||
|
return _fmt(await _request("GET", "/status"))
|
||||||
|
|
||||||
|
|
||||||
|
@mcp.tool()
|
||||||
|
async def get_blocks(x1: int, y1: int, z1: int, x2: int, y2: int, z2: int) -> str:
|
||||||
|
"""Get all blocks in a bounding box. Returns a 3D array of block IDs.
|
||||||
|
Max volume is 32x32x32 blocks."""
|
||||||
|
return _fmt(await _request("GET", "/blocks", params={
|
||||||
|
"x1": x1, "y1": y1, "z1": z1,
|
||||||
|
"x2": x2, "y2": y2, "z2": z2,
|
||||||
|
}))
|
||||||
|
|
||||||
|
|
||||||
|
@mcp.tool()
|
||||||
|
async def get_block(x: int, y: int, z: int) -> str:
|
||||||
|
"""Get the block type and properties at the given coordinates."""
|
||||||
|
return _fmt(await _request("GET", "/block", params={"x": x, "y": y, "z": z}))
|
||||||
|
|
||||||
|
|
||||||
|
@mcp.tool()
|
||||||
|
async def get_nearby_entities(radius: int = 16) -> str:
|
||||||
|
"""Get entities near the bot. Returns type, name, position, and distance.
|
||||||
|
Radius defaults to 16, max 64."""
|
||||||
|
return _fmt(await _request("GET", "/nearby_entities", params={"radius": radius}))
|
||||||
|
|
||||||
|
|
||||||
|
@mcp.tool()
|
||||||
|
async def get_inventory() -> str:
|
||||||
|
"""Get the bot's inventory. Returns slot number, item ID, and count for each item."""
|
||||||
|
return _fmt(await _request("GET", "/inventory"))
|
||||||
|
|
||||||
|
|
||||||
|
@mcp.tool()
|
||||||
|
async def get_biome(x: int, z: int) -> str:
|
||||||
|
"""Get the biome at the given X/Z coordinates (uses bot's current Y)."""
|
||||||
|
return _fmt(await _request("GET", "/biome", params={"x": x, "z": z}))
|
||||||
|
|
||||||
|
|
||||||
|
@mcp.tool()
|
||||||
|
async def list_block_types(filter: str = "") -> str:
|
||||||
|
"""List all available block type IDs, optionally filtered by a substring."""
|
||||||
|
return _fmt(await _request("GET", "/block_types", params={"filter": filter}))
|
||||||
|
|
||||||
|
|
||||||
|
@mcp.tool()
|
||||||
|
async def get_time() -> str:
|
||||||
|
"""Get the current world time. Returns total game ticks, day-time ticks, and whether it is daytime."""
|
||||||
|
return _fmt(await _request("GET", "/get_time"))
|
||||||
|
|
||||||
|
|
||||||
|
@mcp.tool()
|
||||||
|
async def get_weather() -> str:
|
||||||
|
"""Get the current weather. Returns whether it is raining and/or thundering."""
|
||||||
|
return _fmt(await _request("GET", "/get_weather"))
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Action tools (POST)
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
@mcp.tool()
|
||||||
|
async def move_to(x: float, y: float, z: float) -> str:
|
||||||
|
"""Move the bot to the given coordinates by pathfinding. Returns distance moved."""
|
||||||
|
return _fmt(await _request("POST", "/move_to", json={"x": x, "y": y, "z": z}))
|
||||||
|
|
||||||
|
|
||||||
|
@mcp.tool()
|
||||||
|
async def teleport(x: float, y: float, z: float) -> str:
|
||||||
|
"""Teleport the bot instantly to the given coordinates."""
|
||||||
|
return _fmt(await _request("POST", "/teleport", json={"x": x, "y": y, "z": z}))
|
||||||
|
|
||||||
|
|
||||||
|
@mcp.tool()
|
||||||
|
async def place_block(x: int, y: int, z: int, block_type: str) -> str:
|
||||||
|
"""Place a block at the given coordinates. block_type is a Minecraft block ID like 'stone' or 'oak_planks'."""
|
||||||
|
return _fmt(await _request("POST", "/place_block", json={
|
||||||
|
"x": x, "y": y, "z": z, "type": block_type,
|
||||||
|
}))
|
||||||
|
|
||||||
|
|
||||||
|
@mcp.tool()
|
||||||
|
async def place_blocks(blocks: list[dict]) -> str:
|
||||||
|
"""Place multiple blocks at once. Each entry is {x, y, z, type}. Max 10,000 blocks per call."""
|
||||||
|
return _fmt(await _request("POST", "/place_blocks", json={"blocks": blocks}))
|
||||||
|
|
||||||
|
|
||||||
|
@mcp.tool()
|
||||||
|
async def fill(x1: int, y1: int, z1: int, x2: int, y2: int, z2: int, block_type: str) -> str:
|
||||||
|
"""Fill a bounding box with a single block type. Max volume 32x32x32."""
|
||||||
|
return _fmt(await _request("POST", "/fill", json={
|
||||||
|
"x1": x1, "y1": y1, "z1": z1,
|
||||||
|
"x2": x2, "y2": y2, "z2": z2,
|
||||||
|
"type": block_type,
|
||||||
|
}))
|
||||||
|
|
||||||
|
|
||||||
|
@mcp.tool()
|
||||||
|
async def break_block(x: int, y: int, z: int) -> str:
|
||||||
|
"""Break (destroy) the block at the given coordinates."""
|
||||||
|
return _fmt(await _request("POST", "/break_block", json={"x": x, "y": y, "z": z}))
|
||||||
|
|
||||||
|
|
||||||
|
@mcp.tool()
|
||||||
|
async def clear_area(x1: int, y1: int, z1: int, x2: int, y2: int, z2: int) -> str:
|
||||||
|
"""Clear all blocks in a bounding box (replace with air). Max volume 64x64x64."""
|
||||||
|
return _fmt(await _request("POST", "/clear_area", json={
|
||||||
|
"x1": x1, "y1": y1, "z1": z1,
|
||||||
|
"x2": x2, "y2": y2, "z2": z2,
|
||||||
|
}))
|
||||||
|
|
||||||
|
|
||||||
|
@mcp.tool()
|
||||||
|
async def place_structure(
|
||||||
|
origin_x: int, origin_y: int, origin_z: int,
|
||||||
|
palette: dict[str, str], layers: list[list[str]]
|
||||||
|
) -> str:
|
||||||
|
"""Place a structure defined by a palette and layer strings.
|
||||||
|
|
||||||
|
Each palette key is a single character mapped to a block ID (e.g. {"1": "minecraft:stone"}).
|
||||||
|
Layers is a list of Y-slices (bottom to top). Each slice is a list of Z-row strings.
|
||||||
|
Each character in a row string places one block along X. Spaces are skipped (air).
|
||||||
|
|
||||||
|
Example — a 3x3x3 hollow stone cube:
|
||||||
|
palette: {"1": "minecraft:stone"}
|
||||||
|
layers: [
|
||||||
|
["111", "111", "111"], # bottom (solid)
|
||||||
|
["111", "1 1", "111"], # middle (hollow)
|
||||||
|
["111", "111", "111"] # top (solid)
|
||||||
|
]
|
||||||
|
|
||||||
|
Max 64 blocks in any dimension.
|
||||||
|
"""
|
||||||
|
return _fmt(await _request("POST", "/place_structure", json={
|
||||||
|
"origin": {"x": origin_x, "y": origin_y, "z": origin_z},
|
||||||
|
"palette": palette,
|
||||||
|
"layers": layers,
|
||||||
|
}, timeout=30.0))
|
||||||
|
|
||||||
|
|
||||||
|
@mcp.tool()
|
||||||
|
async def save_schematic(name: str, x1: int, y1: int, z1: int, x2: int, y2: int, z2: int) -> str:
|
||||||
|
"""Save all non-air blocks in a bounding box to a named schematic file.
|
||||||
|
Name may only contain letters, numbers, underscore, and hyphen.
|
||||||
|
Max volume 64x64x64. Schematics are saved in the world's schematics folder."""
|
||||||
|
return _fmt(await _request("POST", "/save_schematic", json={
|
||||||
|
"name": name,
|
||||||
|
"x1": x1, "y1": y1, "z1": z1,
|
||||||
|
"x2": x2, "y2": y2, "z2": z2,
|
||||||
|
}, timeout=15.0))
|
||||||
|
|
||||||
|
|
||||||
|
@mcp.tool()
|
||||||
|
async def load_schematic(name: str, x: int, y: int, z: int) -> str:
|
||||||
|
"""Load a previously saved schematic and place it at the given origin coordinates.
|
||||||
|
Name may only contain letters, numbers, underscore, and hyphen."""
|
||||||
|
return _fmt(await _request("POST", "/load_schematic", json={
|
||||||
|
"name": name, "x": x, "y": y, "z": z,
|
||||||
|
}, timeout=30.0))
|
||||||
|
|
||||||
|
|
||||||
|
@mcp.tool()
|
||||||
|
async def set_state(state: str) -> str:
|
||||||
|
"""Set the bot's visual state. Valid states: idle, thinking, building, moving."""
|
||||||
|
return _fmt(await _request("POST", "/set_state", json={"state": state}))
|
||||||
|
|
||||||
|
|
||||||
|
@mcp.tool()
|
||||||
|
async def look_at(x: float, y: float, z: float) -> str:
|
||||||
|
"""Make the bot look at the given coordinates."""
|
||||||
|
return _fmt(await _request("POST", "/look_at", json={"x": x, "y": y, "z": z}))
|
||||||
|
|
||||||
|
|
||||||
|
@mcp.tool()
|
||||||
|
async def chat(message: str) -> str:
|
||||||
|
"""Send a chat message in-game as the bot."""
|
||||||
|
return _fmt(await _request("POST", "/chat", json={"message": message}))
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Interaction tool (long-poll)
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
@mcp.tool()
|
||||||
|
async def wait_for_instruction() -> str:
|
||||||
|
"""Wait for a player to send a !clod command in Minecraft chat.
|
||||||
|
Long-polls for up to 300 seconds. Returns {player, message} or {timeout: true}.
|
||||||
|
The !clod prefix is already stripped by the mod."""
|
||||||
|
return _fmt(await _request("GET", "/chat/wait", timeout=310.0))
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Entry point
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
mcp.run(transport="stdio")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@@ -0,0 +1,511 @@
|
|||||||
|
package net.minecraft.client.model;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import net.minecraft.client.model.geom.ModelPart;
|
||||||
|
import net.minecraft.client.model.geom.PartPose;
|
||||||
|
import net.minecraft.client.model.geom.builders.CubeDeformation;
|
||||||
|
import net.minecraft.client.model.geom.builders.CubeListBuilder;
|
||||||
|
import net.minecraft.client.model.geom.builders.MeshDefinition;
|
||||||
|
import net.minecraft.client.model.geom.builders.PartDefinition;
|
||||||
|
import net.minecraft.client.renderer.RenderType;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.util.Mth;
|
||||||
|
import net.minecraft.world.InteractionHand;
|
||||||
|
import net.minecraft.world.entity.HumanoidArm;
|
||||||
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
|
import net.neoforged.api.distmarker.Dist;
|
||||||
|
import net.neoforged.api.distmarker.OnlyIn;
|
||||||
|
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
public class HumanoidModel<T extends LivingEntity> extends AgeableListModel<T> implements ArmedModel, HeadedModel {
|
||||||
|
public static final float OVERLAY_SCALE = 0.25F;
|
||||||
|
public static final float HAT_OVERLAY_SCALE = 0.5F;
|
||||||
|
public static final float LEGGINGS_OVERLAY_SCALE = -0.1F;
|
||||||
|
private static final float DUCK_WALK_ROTATION = 0.005F;
|
||||||
|
private static final float SPYGLASS_ARM_ROT_Y = (float) (Math.PI / 12);
|
||||||
|
private static final float SPYGLASS_ARM_ROT_X = 1.9198622F;
|
||||||
|
private static final float SPYGLASS_ARM_CROUCH_ROT_X = (float) (Math.PI / 12);
|
||||||
|
private static final float HIGHEST_SHIELD_BLOCKING_ANGLE = (float) (-Math.PI * 4.0 / 9.0);
|
||||||
|
private static final float LOWEST_SHIELD_BLOCKING_ANGLE = 0.43633232F;
|
||||||
|
private static final float HORIZONTAL_SHIELD_MOVEMENT_LIMIT = (float) (Math.PI / 6);
|
||||||
|
public static final float TOOT_HORN_XROT_BASE = 1.4835298F;
|
||||||
|
public static final float TOOT_HORN_YROT_BASE = (float) (Math.PI / 6);
|
||||||
|
public final ModelPart head;
|
||||||
|
/**
|
||||||
|
* The Biped's Headwear. Used for the outer layer of player skins.
|
||||||
|
*/
|
||||||
|
public final ModelPart hat;
|
||||||
|
public final ModelPart body;
|
||||||
|
/**
|
||||||
|
* The Biped's Right Arm
|
||||||
|
*/
|
||||||
|
public final ModelPart rightArm;
|
||||||
|
/**
|
||||||
|
* The Biped's Left Arm
|
||||||
|
*/
|
||||||
|
public final ModelPart leftArm;
|
||||||
|
/**
|
||||||
|
* The Biped's Right Leg
|
||||||
|
*/
|
||||||
|
public final ModelPart rightLeg;
|
||||||
|
/**
|
||||||
|
* The Biped's Left Leg
|
||||||
|
*/
|
||||||
|
public final ModelPart leftLeg;
|
||||||
|
public HumanoidModel.ArmPose leftArmPose = HumanoidModel.ArmPose.EMPTY;
|
||||||
|
public HumanoidModel.ArmPose rightArmPose = HumanoidModel.ArmPose.EMPTY;
|
||||||
|
public boolean crouching;
|
||||||
|
public float swimAmount;
|
||||||
|
|
||||||
|
public HumanoidModel(ModelPart root) {
|
||||||
|
this(root, RenderType::entityCutoutNoCull);
|
||||||
|
}
|
||||||
|
|
||||||
|
public HumanoidModel(ModelPart root, Function<ResourceLocation, RenderType> renderType) {
|
||||||
|
super(renderType, true, 16.0F, 0.0F, 2.0F, 2.0F, 24.0F);
|
||||||
|
this.head = root.getChild("head");
|
||||||
|
this.hat = root.getChild("hat");
|
||||||
|
this.body = root.getChild("body");
|
||||||
|
this.rightArm = root.getChild("right_arm");
|
||||||
|
this.leftArm = root.getChild("left_arm");
|
||||||
|
this.rightLeg = root.getChild("right_leg");
|
||||||
|
this.leftLeg = root.getChild("left_leg");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MeshDefinition createMesh(CubeDeformation cubeDeformation, float yOffset) {
|
||||||
|
MeshDefinition meshdefinition = new MeshDefinition();
|
||||||
|
PartDefinition partdefinition = meshdefinition.getRoot();
|
||||||
|
partdefinition.addOrReplaceChild(
|
||||||
|
"head",
|
||||||
|
CubeListBuilder.create().texOffs(0, 0).addBox(-4.0F, -8.0F, -4.0F, 8.0F, 8.0F, 8.0F, cubeDeformation),
|
||||||
|
PartPose.offset(0.0F, 0.0F + yOffset, 0.0F)
|
||||||
|
);
|
||||||
|
partdefinition.addOrReplaceChild(
|
||||||
|
"hat",
|
||||||
|
CubeListBuilder.create().texOffs(32, 0).addBox(-4.0F, -8.0F, -4.0F, 8.0F, 8.0F, 8.0F, cubeDeformation.extend(0.5F)),
|
||||||
|
PartPose.offset(0.0F, 0.0F + yOffset, 0.0F)
|
||||||
|
);
|
||||||
|
partdefinition.addOrReplaceChild(
|
||||||
|
"body",
|
||||||
|
CubeListBuilder.create().texOffs(16, 16).addBox(-4.0F, 0.0F, -2.0F, 8.0F, 12.0F, 4.0F, cubeDeformation),
|
||||||
|
PartPose.offset(0.0F, 0.0F + yOffset, 0.0F)
|
||||||
|
);
|
||||||
|
partdefinition.addOrReplaceChild(
|
||||||
|
"right_arm",
|
||||||
|
CubeListBuilder.create().texOffs(40, 16).addBox(-3.0F, -2.0F, -2.0F, 4.0F, 12.0F, 4.0F, cubeDeformation),
|
||||||
|
PartPose.offset(-5.0F, 2.0F + yOffset, 0.0F)
|
||||||
|
);
|
||||||
|
partdefinition.addOrReplaceChild(
|
||||||
|
"left_arm",
|
||||||
|
CubeListBuilder.create().texOffs(40, 16).mirror().addBox(-1.0F, -2.0F, -2.0F, 4.0F, 12.0F, 4.0F, cubeDeformation),
|
||||||
|
PartPose.offset(5.0F, 2.0F + yOffset, 0.0F)
|
||||||
|
);
|
||||||
|
partdefinition.addOrReplaceChild(
|
||||||
|
"right_leg",
|
||||||
|
CubeListBuilder.create().texOffs(0, 16).addBox(-2.0F, 0.0F, -2.0F, 4.0F, 12.0F, 4.0F, cubeDeformation),
|
||||||
|
PartPose.offset(-1.9F, 12.0F + yOffset, 0.0F)
|
||||||
|
);
|
||||||
|
partdefinition.addOrReplaceChild(
|
||||||
|
"left_leg",
|
||||||
|
CubeListBuilder.create().texOffs(0, 16).mirror().addBox(-2.0F, 0.0F, -2.0F, 4.0F, 12.0F, 4.0F, cubeDeformation),
|
||||||
|
PartPose.offset(1.9F, 12.0F + yOffset, 0.0F)
|
||||||
|
);
|
||||||
|
return meshdefinition;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Iterable<ModelPart> headParts() {
|
||||||
|
return ImmutableList.of(this.head);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Iterable<ModelPart> bodyParts() {
|
||||||
|
return ImmutableList.of(this.body, this.rightArm, this.leftArm, this.rightLeg, this.leftLeg, this.hat);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void prepareMobModel(T entity, float limbSwing, float limbSwingAmount, float partialTick) {
|
||||||
|
this.swimAmount = entity.getSwimAmount(partialTick);
|
||||||
|
super.prepareMobModel(entity, limbSwing, limbSwingAmount, partialTick);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets this entity's model rotation angles
|
||||||
|
*/
|
||||||
|
public void setupAnim(T entity, float limbSwing, float limbSwingAmount, float ageInTicks, float netHeadYaw, float headPitch) {
|
||||||
|
boolean flag = entity.getFallFlyingTicks() > 4;
|
||||||
|
boolean flag1 = entity.isVisuallySwimming();
|
||||||
|
this.head.yRot = netHeadYaw * (float) (Math.PI / 180.0);
|
||||||
|
if (flag) {
|
||||||
|
this.head.xRot = (float) (-Math.PI / 4);
|
||||||
|
} else if (this.swimAmount > 0.0F) {
|
||||||
|
if (flag1) {
|
||||||
|
this.head.xRot = this.rotlerpRad(this.swimAmount, this.head.xRot, (float) (-Math.PI / 4));
|
||||||
|
} else {
|
||||||
|
this.head.xRot = this.rotlerpRad(this.swimAmount, this.head.xRot, headPitch * (float) (Math.PI / 180.0));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.head.xRot = headPitch * (float) (Math.PI / 180.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.body.yRot = 0.0F;
|
||||||
|
this.rightArm.z = 0.0F;
|
||||||
|
this.rightArm.x = -5.0F;
|
||||||
|
this.leftArm.z = 0.0F;
|
||||||
|
this.leftArm.x = 5.0F;
|
||||||
|
float f = 1.0F;
|
||||||
|
if (flag) {
|
||||||
|
f = (float)entity.getDeltaMovement().lengthSqr();
|
||||||
|
f /= 0.2F;
|
||||||
|
f *= f * f;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (f < 1.0F) {
|
||||||
|
f = 1.0F;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.rightArm.xRot = Mth.cos(limbSwing * 0.6662F + (float) Math.PI) * 2.0F * limbSwingAmount * 0.5F / f;
|
||||||
|
this.leftArm.xRot = Mth.cos(limbSwing * 0.6662F) * 2.0F * limbSwingAmount * 0.5F / f;
|
||||||
|
this.rightArm.zRot = 0.0F;
|
||||||
|
this.leftArm.zRot = 0.0F;
|
||||||
|
this.rightLeg.xRot = Mth.cos(limbSwing * 0.6662F) * 1.4F * limbSwingAmount / f;
|
||||||
|
this.leftLeg.xRot = Mth.cos(limbSwing * 0.6662F + (float) Math.PI) * 1.4F * limbSwingAmount / f;
|
||||||
|
this.rightLeg.yRot = 0.005F;
|
||||||
|
this.leftLeg.yRot = -0.005F;
|
||||||
|
this.rightLeg.zRot = 0.005F;
|
||||||
|
this.leftLeg.zRot = -0.005F;
|
||||||
|
if (this.riding) {
|
||||||
|
this.rightArm.xRot += (float) (-Math.PI / 5);
|
||||||
|
this.leftArm.xRot += (float) (-Math.PI / 5);
|
||||||
|
this.rightLeg.xRot = -1.4137167F;
|
||||||
|
this.rightLeg.yRot = (float) (Math.PI / 10);
|
||||||
|
this.rightLeg.zRot = 0.07853982F;
|
||||||
|
this.leftLeg.xRot = -1.4137167F;
|
||||||
|
this.leftLeg.yRot = (float) (-Math.PI / 10);
|
||||||
|
this.leftLeg.zRot = -0.07853982F;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.rightArm.yRot = 0.0F;
|
||||||
|
this.leftArm.yRot = 0.0F;
|
||||||
|
boolean flag2 = entity.getMainArm() == HumanoidArm.RIGHT;
|
||||||
|
if (entity.isUsingItem()) {
|
||||||
|
boolean flag3 = entity.getUsedItemHand() == InteractionHand.MAIN_HAND;
|
||||||
|
if (flag3 == flag2) {
|
||||||
|
this.poseRightArm(entity);
|
||||||
|
} else {
|
||||||
|
this.poseLeftArm(entity);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
boolean flag4 = flag2 ? this.leftArmPose.isTwoHanded() : this.rightArmPose.isTwoHanded();
|
||||||
|
if (flag2 != flag4) {
|
||||||
|
this.poseLeftArm(entity);
|
||||||
|
this.poseRightArm(entity);
|
||||||
|
} else {
|
||||||
|
this.poseRightArm(entity);
|
||||||
|
this.poseLeftArm(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setupAttackAnimation(entity, ageInTicks);
|
||||||
|
if (this.crouching) {
|
||||||
|
this.body.xRot = 0.5F;
|
||||||
|
this.rightArm.xRot += 0.4F;
|
||||||
|
this.leftArm.xRot += 0.4F;
|
||||||
|
this.rightLeg.z = 4.0F;
|
||||||
|
this.leftLeg.z = 4.0F;
|
||||||
|
this.rightLeg.y = 12.2F;
|
||||||
|
this.leftLeg.y = 12.2F;
|
||||||
|
this.head.y = 4.2F;
|
||||||
|
this.body.y = 3.2F;
|
||||||
|
this.leftArm.y = 5.2F;
|
||||||
|
this.rightArm.y = 5.2F;
|
||||||
|
} else {
|
||||||
|
this.body.xRot = 0.0F;
|
||||||
|
this.rightLeg.z = 0.0F;
|
||||||
|
this.leftLeg.z = 0.0F;
|
||||||
|
this.rightLeg.y = 12.0F;
|
||||||
|
this.leftLeg.y = 12.0F;
|
||||||
|
this.head.y = 0.0F;
|
||||||
|
this.body.y = 0.0F;
|
||||||
|
this.leftArm.y = 2.0F;
|
||||||
|
this.rightArm.y = 2.0F;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.rightArmPose != HumanoidModel.ArmPose.SPYGLASS) {
|
||||||
|
AnimationUtils.bobModelPart(this.rightArm, ageInTicks, 1.0F);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.leftArmPose != HumanoidModel.ArmPose.SPYGLASS) {
|
||||||
|
AnimationUtils.bobModelPart(this.leftArm, ageInTicks, -1.0F);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.swimAmount > 0.0F) {
|
||||||
|
float f5 = limbSwing % 26.0F;
|
||||||
|
HumanoidArm humanoidarm = this.getAttackArm(entity);
|
||||||
|
float f1 = humanoidarm == HumanoidArm.RIGHT && this.attackTime > 0.0F ? 0.0F : this.swimAmount;
|
||||||
|
float f2 = humanoidarm == HumanoidArm.LEFT && this.attackTime > 0.0F ? 0.0F : this.swimAmount;
|
||||||
|
if (!entity.isUsingItem()) {
|
||||||
|
if (f5 < 14.0F) {
|
||||||
|
this.leftArm.xRot = this.rotlerpRad(f2, this.leftArm.xRot, 0.0F);
|
||||||
|
this.rightArm.xRot = Mth.lerp(f1, this.rightArm.xRot, 0.0F);
|
||||||
|
this.leftArm.yRot = this.rotlerpRad(f2, this.leftArm.yRot, (float) Math.PI);
|
||||||
|
this.rightArm.yRot = Mth.lerp(f1, this.rightArm.yRot, (float) Math.PI);
|
||||||
|
this.leftArm.zRot = this.rotlerpRad(
|
||||||
|
f2, this.leftArm.zRot, (float) Math.PI + 1.8707964F * this.quadraticArmUpdate(f5) / this.quadraticArmUpdate(14.0F)
|
||||||
|
);
|
||||||
|
this.rightArm.zRot = Mth.lerp(
|
||||||
|
f1, this.rightArm.zRot, (float) Math.PI - 1.8707964F * this.quadraticArmUpdate(f5) / this.quadraticArmUpdate(14.0F)
|
||||||
|
);
|
||||||
|
} else if (f5 >= 14.0F && f5 < 22.0F) {
|
||||||
|
float f6 = (f5 - 14.0F) / 8.0F;
|
||||||
|
this.leftArm.xRot = this.rotlerpRad(f2, this.leftArm.xRot, (float) (Math.PI / 2) * f6);
|
||||||
|
this.rightArm.xRot = Mth.lerp(f1, this.rightArm.xRot, (float) (Math.PI / 2) * f6);
|
||||||
|
this.leftArm.yRot = this.rotlerpRad(f2, this.leftArm.yRot, (float) Math.PI);
|
||||||
|
this.rightArm.yRot = Mth.lerp(f1, this.rightArm.yRot, (float) Math.PI);
|
||||||
|
this.leftArm.zRot = this.rotlerpRad(f2, this.leftArm.zRot, 5.012389F - 1.8707964F * f6);
|
||||||
|
this.rightArm.zRot = Mth.lerp(f1, this.rightArm.zRot, 1.2707963F + 1.8707964F * f6);
|
||||||
|
} else if (f5 >= 22.0F && f5 < 26.0F) {
|
||||||
|
float f3 = (f5 - 22.0F) / 4.0F;
|
||||||
|
this.leftArm.xRot = this.rotlerpRad(f2, this.leftArm.xRot, (float) (Math.PI / 2) - (float) (Math.PI / 2) * f3);
|
||||||
|
this.rightArm.xRot = Mth.lerp(f1, this.rightArm.xRot, (float) (Math.PI / 2) - (float) (Math.PI / 2) * f3);
|
||||||
|
this.leftArm.yRot = this.rotlerpRad(f2, this.leftArm.yRot, (float) Math.PI);
|
||||||
|
this.rightArm.yRot = Mth.lerp(f1, this.rightArm.yRot, (float) Math.PI);
|
||||||
|
this.leftArm.zRot = this.rotlerpRad(f2, this.leftArm.zRot, (float) Math.PI);
|
||||||
|
this.rightArm.zRot = Mth.lerp(f1, this.rightArm.zRot, (float) Math.PI);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float f7 = 0.3F;
|
||||||
|
float f4 = 0.33333334F;
|
||||||
|
this.leftLeg.xRot = Mth.lerp(this.swimAmount, this.leftLeg.xRot, 0.3F * Mth.cos(limbSwing * 0.33333334F + (float) Math.PI));
|
||||||
|
this.rightLeg.xRot = Mth.lerp(this.swimAmount, this.rightLeg.xRot, 0.3F * Mth.cos(limbSwing * 0.33333334F));
|
||||||
|
}
|
||||||
|
|
||||||
|
this.hat.copyFrom(this.head);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void poseRightArm(T livingEntity) {
|
||||||
|
switch (this.rightArmPose) {
|
||||||
|
case EMPTY:
|
||||||
|
this.rightArm.yRot = 0.0F;
|
||||||
|
break;
|
||||||
|
case ITEM:
|
||||||
|
this.rightArm.xRot = this.rightArm.xRot * 0.5F - (float) (Math.PI / 10);
|
||||||
|
this.rightArm.yRot = 0.0F;
|
||||||
|
break;
|
||||||
|
case BLOCK:
|
||||||
|
this.poseBlockingArm(this.rightArm, true);
|
||||||
|
break;
|
||||||
|
case BOW_AND_ARROW:
|
||||||
|
this.rightArm.yRot = -0.1F + this.head.yRot;
|
||||||
|
this.leftArm.yRot = 0.1F + this.head.yRot + 0.4F;
|
||||||
|
this.rightArm.xRot = (float) (-Math.PI / 2) + this.head.xRot;
|
||||||
|
this.leftArm.xRot = (float) (-Math.PI / 2) + this.head.xRot;
|
||||||
|
break;
|
||||||
|
case THROW_SPEAR:
|
||||||
|
this.rightArm.xRot = this.rightArm.xRot * 0.5F - (float) Math.PI;
|
||||||
|
this.rightArm.yRot = 0.0F;
|
||||||
|
break;
|
||||||
|
case CROSSBOW_CHARGE:
|
||||||
|
AnimationUtils.animateCrossbowCharge(this.rightArm, this.leftArm, livingEntity, true);
|
||||||
|
break;
|
||||||
|
case CROSSBOW_HOLD:
|
||||||
|
AnimationUtils.animateCrossbowHold(this.rightArm, this.leftArm, this.head, true);
|
||||||
|
break;
|
||||||
|
case SPYGLASS:
|
||||||
|
this.rightArm.xRot = Mth.clamp(this.head.xRot - 1.9198622F - (livingEntity.isCrouching() ? (float) (Math.PI / 12) : 0.0F), -2.4F, 3.3F);
|
||||||
|
this.rightArm.yRot = this.head.yRot - (float) (Math.PI / 12);
|
||||||
|
break;
|
||||||
|
case TOOT_HORN:
|
||||||
|
this.rightArm.xRot = Mth.clamp(this.head.xRot, -1.2F, 1.2F) - 1.4835298F;
|
||||||
|
this.rightArm.yRot = this.head.yRot - (float) (Math.PI / 6);
|
||||||
|
break;
|
||||||
|
case BRUSH:
|
||||||
|
this.rightArm.xRot = this.rightArm.xRot * 0.5F - (float) (Math.PI / 5);
|
||||||
|
this.rightArm.yRot = 0.0F;
|
||||||
|
default:
|
||||||
|
this.rightArmPose.applyTransform(this, livingEntity, net.minecraft.world.entity.HumanoidArm.RIGHT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void poseLeftArm(T livingEntity) {
|
||||||
|
switch (this.leftArmPose) {
|
||||||
|
case EMPTY:
|
||||||
|
this.leftArm.yRot = 0.0F;
|
||||||
|
break;
|
||||||
|
case ITEM:
|
||||||
|
this.leftArm.xRot = this.leftArm.xRot * 0.5F - (float) (Math.PI / 10);
|
||||||
|
this.leftArm.yRot = 0.0F;
|
||||||
|
break;
|
||||||
|
case BLOCK:
|
||||||
|
this.poseBlockingArm(this.leftArm, false);
|
||||||
|
break;
|
||||||
|
case BOW_AND_ARROW:
|
||||||
|
this.rightArm.yRot = -0.1F + this.head.yRot - 0.4F;
|
||||||
|
this.leftArm.yRot = 0.1F + this.head.yRot;
|
||||||
|
this.rightArm.xRot = (float) (-Math.PI / 2) + this.head.xRot;
|
||||||
|
this.leftArm.xRot = (float) (-Math.PI / 2) + this.head.xRot;
|
||||||
|
break;
|
||||||
|
case THROW_SPEAR:
|
||||||
|
this.leftArm.xRot = this.leftArm.xRot * 0.5F - (float) Math.PI;
|
||||||
|
this.leftArm.yRot = 0.0F;
|
||||||
|
break;
|
||||||
|
case CROSSBOW_CHARGE:
|
||||||
|
AnimationUtils.animateCrossbowCharge(this.rightArm, this.leftArm, livingEntity, false);
|
||||||
|
break;
|
||||||
|
case CROSSBOW_HOLD:
|
||||||
|
AnimationUtils.animateCrossbowHold(this.rightArm, this.leftArm, this.head, false);
|
||||||
|
break;
|
||||||
|
case SPYGLASS:
|
||||||
|
this.leftArm.xRot = Mth.clamp(this.head.xRot - 1.9198622F - (livingEntity.isCrouching() ? (float) (Math.PI / 12) : 0.0F), -2.4F, 3.3F);
|
||||||
|
this.leftArm.yRot = this.head.yRot + (float) (Math.PI / 12);
|
||||||
|
break;
|
||||||
|
case TOOT_HORN:
|
||||||
|
this.leftArm.xRot = Mth.clamp(this.head.xRot, -1.2F, 1.2F) - 1.4835298F;
|
||||||
|
this.leftArm.yRot = this.head.yRot + (float) (Math.PI / 6);
|
||||||
|
break;
|
||||||
|
case BRUSH:
|
||||||
|
this.leftArm.xRot = this.leftArm.xRot * 0.5F - (float) (Math.PI / 5);
|
||||||
|
this.leftArm.yRot = 0.0F;
|
||||||
|
default:
|
||||||
|
this.leftArmPose.applyTransform(this, livingEntity, net.minecraft.world.entity.HumanoidArm.LEFT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void poseBlockingArm(ModelPart arm, boolean isRightArm) {
|
||||||
|
arm.xRot = arm.xRot * 0.5F - 0.9424779F + Mth.clamp(this.head.xRot, (float) (-Math.PI * 4.0 / 9.0), 0.43633232F);
|
||||||
|
arm.yRot = (isRightArm ? -30.0F : 30.0F) * (float) (Math.PI / 180.0) + Mth.clamp(this.head.yRot, (float) (-Math.PI / 6), (float) (Math.PI / 6));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setupAttackAnimation(T livingEntity, float ageInTicks) {
|
||||||
|
if (!(this.attackTime <= 0.0F)) {
|
||||||
|
HumanoidArm humanoidarm = this.getAttackArm(livingEntity);
|
||||||
|
ModelPart modelpart = this.getArm(humanoidarm);
|
||||||
|
float f = this.attackTime;
|
||||||
|
this.body.yRot = Mth.sin(Mth.sqrt(f) * (float) (Math.PI * 2)) * 0.2F;
|
||||||
|
if (humanoidarm == HumanoidArm.LEFT) {
|
||||||
|
this.body.yRot *= -1.0F;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.rightArm.z = Mth.sin(this.body.yRot) * 5.0F;
|
||||||
|
this.rightArm.x = -Mth.cos(this.body.yRot) * 5.0F;
|
||||||
|
this.leftArm.z = -Mth.sin(this.body.yRot) * 5.0F;
|
||||||
|
this.leftArm.x = Mth.cos(this.body.yRot) * 5.0F;
|
||||||
|
this.rightArm.yRot = this.rightArm.yRot + this.body.yRot;
|
||||||
|
this.leftArm.yRot = this.leftArm.yRot + this.body.yRot;
|
||||||
|
this.leftArm.xRot = this.leftArm.xRot + this.body.yRot;
|
||||||
|
f = 1.0F - this.attackTime;
|
||||||
|
f *= f;
|
||||||
|
f *= f;
|
||||||
|
f = 1.0F - f;
|
||||||
|
float f1 = Mth.sin(f * (float) Math.PI);
|
||||||
|
float f2 = Mth.sin(this.attackTime * (float) Math.PI) * -(this.head.xRot - 0.7F) * 0.75F;
|
||||||
|
modelpart.xRot -= f1 * 1.2F + f2;
|
||||||
|
modelpart.yRot = modelpart.yRot + this.body.yRot * 2.0F;
|
||||||
|
modelpart.zRot = modelpart.zRot + Mth.sin(this.attackTime * (float) Math.PI) * -0.4F;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected float rotlerpRad(float angle, float maxAngle, float mul) {
|
||||||
|
float f = (mul - maxAngle) % (float) (Math.PI * 2);
|
||||||
|
if (f < (float) -Math.PI) {
|
||||||
|
f += (float) (Math.PI * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (f >= (float) Math.PI) {
|
||||||
|
f -= (float) (Math.PI * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
return maxAngle + angle * f;
|
||||||
|
}
|
||||||
|
|
||||||
|
private float quadraticArmUpdate(float limbSwing) {
|
||||||
|
return -65.0F * limbSwing + limbSwing * limbSwing;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void copyPropertiesTo(HumanoidModel<T> model) {
|
||||||
|
super.copyPropertiesTo(model);
|
||||||
|
model.leftArmPose = this.leftArmPose;
|
||||||
|
model.rightArmPose = this.rightArmPose;
|
||||||
|
model.crouching = this.crouching;
|
||||||
|
model.head.copyFrom(this.head);
|
||||||
|
model.hat.copyFrom(this.hat);
|
||||||
|
model.body.copyFrom(this.body);
|
||||||
|
model.rightArm.copyFrom(this.rightArm);
|
||||||
|
model.leftArm.copyFrom(this.leftArm);
|
||||||
|
model.rightLeg.copyFrom(this.rightLeg);
|
||||||
|
model.leftLeg.copyFrom(this.leftLeg);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAllVisible(boolean visible) {
|
||||||
|
this.head.visible = visible;
|
||||||
|
this.hat.visible = visible;
|
||||||
|
this.body.visible = visible;
|
||||||
|
this.rightArm.visible = visible;
|
||||||
|
this.leftArm.visible = visible;
|
||||||
|
this.rightLeg.visible = visible;
|
||||||
|
this.leftLeg.visible = visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void translateToHand(HumanoidArm side, PoseStack poseStack) {
|
||||||
|
this.getArm(side).translateAndRotate(poseStack);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ModelPart getArm(HumanoidArm side) {
|
||||||
|
return side == HumanoidArm.LEFT ? this.leftArm : this.rightArm;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ModelPart getHead() {
|
||||||
|
return this.head;
|
||||||
|
}
|
||||||
|
|
||||||
|
private HumanoidArm getAttackArm(T entity) {
|
||||||
|
HumanoidArm humanoidarm = entity.getMainArm();
|
||||||
|
return entity.swingingArm == InteractionHand.MAIN_HAND ? humanoidarm : humanoidarm.getOpposite();
|
||||||
|
}
|
||||||
|
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
public static enum ArmPose implements net.neoforged.fml.common.asm.enumextension.IExtensibleEnum {
|
||||||
|
EMPTY(false),
|
||||||
|
ITEM(false),
|
||||||
|
BLOCK(false),
|
||||||
|
BOW_AND_ARROW(true),
|
||||||
|
THROW_SPEAR(false),
|
||||||
|
CROSSBOW_CHARGE(true),
|
||||||
|
CROSSBOW_HOLD(true),
|
||||||
|
SPYGLASS(false),
|
||||||
|
TOOT_HORN(false),
|
||||||
|
BRUSH(false);
|
||||||
|
|
||||||
|
private final boolean twoHanded;
|
||||||
|
@org.jetbrains.annotations.Nullable
|
||||||
|
private final net.neoforged.neoforge.client.IArmPoseTransformer forgeArmPose;
|
||||||
|
|
||||||
|
@net.neoforged.fml.common.asm.enumextension.ReservedConstructor
|
||||||
|
private ArmPose(boolean twoHanded) {
|
||||||
|
this.twoHanded = twoHanded;
|
||||||
|
this.forgeArmPose = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ArmPose(boolean p_twoHanded, net.neoforged.neoforge.client.IArmPoseTransformer forgeArmPose) {
|
||||||
|
this.twoHanded = p_twoHanded;
|
||||||
|
com.google.common.base.Preconditions.checkNotNull(forgeArmPose, "Cannot create new ArmPose with null transformer!");
|
||||||
|
this.forgeArmPose = forgeArmPose;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isTwoHanded() {
|
||||||
|
return this.twoHanded;
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T extends LivingEntity> void applyTransform(HumanoidModel<T> model, T entity, net.minecraft.world.entity.HumanoidArm arm) {
|
||||||
|
if (this.forgeArmPose != null) this.forgeArmPose.applyTransform(model, entity, arm);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static net.neoforged.fml.common.asm.enumextension.ExtensionInfo getExtensionInfo() {
|
||||||
|
return net.neoforged.fml.common.asm.enumextension.ExtensionInfo.nonExtended(HumanoidModel.ArmPose.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package net.minecraft.client.renderer.entity;
|
||||||
|
|
||||||
|
import net.minecraft.client.model.EntityModel;
|
||||||
|
import net.minecraft.world.entity.Mob;
|
||||||
|
import net.neoforged.api.distmarker.Dist;
|
||||||
|
import net.neoforged.api.distmarker.OnlyIn;
|
||||||
|
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
public abstract class MobRenderer<T extends Mob, M extends EntityModel<T>> extends LivingEntityRenderer<T, M> {
|
||||||
|
public MobRenderer(EntityRendererProvider.Context context, M model, float shadowRadius) {
|
||||||
|
super(context, model, shadowRadius);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean shouldShowName(T entity) {
|
||||||
|
return super.shouldShowName(entity)
|
||||||
|
&& (entity.shouldShowName() || entity.hasCustomName() && entity == this.entityRenderDispatcher.crosshairPickEntity);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected float getShadowRadius(T entity) {
|
||||||
|
return super.getShadowRadius(entity) * entity.getAgeScale();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package net.minecraft.client.renderer.entity.layers;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
|
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||||
|
import net.minecraft.client.model.EntityModel;
|
||||||
|
import net.minecraft.client.renderer.MultiBufferSource;
|
||||||
|
import net.minecraft.client.renderer.RenderType;
|
||||||
|
import net.minecraft.client.renderer.entity.RenderLayerParent;
|
||||||
|
import net.minecraft.client.renderer.texture.OverlayTexture;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.neoforged.api.distmarker.Dist;
|
||||||
|
import net.neoforged.api.distmarker.OnlyIn;
|
||||||
|
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
public abstract class EyesLayer<T extends Entity, M extends EntityModel<T>> extends RenderLayer<T, M> {
|
||||||
|
public EyesLayer(RenderLayerParent<T, M> renderer) {
|
||||||
|
super(renderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(
|
||||||
|
PoseStack poseStack,
|
||||||
|
MultiBufferSource buffer,
|
||||||
|
int packedLight,
|
||||||
|
T livingEntity,
|
||||||
|
float limbSwing,
|
||||||
|
float limbSwingAmount,
|
||||||
|
float partialTicks,
|
||||||
|
float ageInTicks,
|
||||||
|
float netHeadYaw,
|
||||||
|
float headPitch
|
||||||
|
) {
|
||||||
|
VertexConsumer vertexconsumer = buffer.getBuffer(this.renderType());
|
||||||
|
this.getParentModel().renderToBuffer(poseStack, vertexconsumer, 15728640, OverlayTexture.NO_OVERLAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract RenderType renderType();
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
/clod spawn
|
||||||
|
/kill
|
||||||
|
/kill clod
|
||||||
|
/kill @e
|
||||||
|
/clod spawn
|
||||||
|
/kill @e
|
||||||
|
/clod spawn
|
||||||
|
/kill @a
|
||||||
|
/kill @e
|
||||||
|
/clode spawn
|
||||||
|
/clod spawn
|
||||||
|
/weather clear
|
||||||
|
/time set day
|
||||||
|
/gamemode survival
|
||||||
|
/gamemode creative
|
||||||
|
/difficulty hard
|
||||||
|
/time set day
|
||||||
|
/time set night
|
||||||
|
/time set 10000
|
||||||
|
/time set 11000
|
||||||
|
/time set 12000
|
||||||
|
/kill @e
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
#Disables File Watcher. Used to automatically update config if its file has been modified.
|
||||||
|
disableConfigWatcher = false
|
||||||
|
#Should we control the window. Disabling this disables new GL features and can be bad for mods that rely on them.
|
||||||
|
earlyWindowControl = true
|
||||||
|
#Max threads for early initialization parallelism, -1 is based on processor count
|
||||||
|
maxThreads = -1
|
||||||
|
#Enable NeoForge global version checking
|
||||||
|
versionCheck = true
|
||||||
|
#Default config path for servers
|
||||||
|
defaultConfigPath = "defaultconfigs"
|
||||||
|
#Disables Optimized DFU client-side - already disabled on servers
|
||||||
|
disableOptimizedDFU = true
|
||||||
|
#Early window provider
|
||||||
|
earlyWindowProvider = "fmlearlywindow"
|
||||||
|
#Early window width
|
||||||
|
earlyWindowWidth = 854
|
||||||
|
#Early window height
|
||||||
|
earlyWindowHeight = 480
|
||||||
|
#Early window framebuffer scale
|
||||||
|
earlyWindowFBScale = 1
|
||||||
|
#Early window starts maximized
|
||||||
|
earlyWindowMaximized = false
|
||||||
|
#Skip specific GL versions, may help with buggy graphics card drivers
|
||||||
|
earlyWindowSkipGLVersions = []
|
||||||
|
#Squir?
|
||||||
|
earlyWindowSquir = false
|
||||||
|
#Define dependency overrides below
|
||||||
|
#Dependency overrides can be used to forcibly remove a dependency constraint from a mod or to force a mod to load AFTER another mod
|
||||||
|
#Using dependency overrides can cause issues. Use at your own risk.
|
||||||
|
#Example dependency override for the mod with the id 'targetMod': dependency constraints (incompatibility clauses or restrictive version ranges) against mod 'dep1' are removed, and the mod will now load after the mod 'dep2'
|
||||||
|
#dependencyOverrides.targetMod = ["-dep1", "+dep2"]
|
||||||
|
dependencyOverrides = {}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
#EXPERIMENTAL: Enable the NeoForge block rendering pipeline - fixes the lighting of custom models.
|
||||||
|
experimentalForgeLightPipelineEnabled = false
|
||||||
|
#When enabled, NeoForge will show any warnings that occurred during loading.
|
||||||
|
showLoadWarnings = true
|
||||||
|
#Set to true to use a combined DEPTH_STENCIL attachment instead of two separate ones.
|
||||||
|
useCombinedDepthStencilAttachment = false
|
||||||
|
#A config option mainly for developers. Logs out configuration values that do not have translations when running a client in a development environment.
|
||||||
|
logUntranslatedConfigurationWarnings = true
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
#A config option mainly for developers. Logs out modded item tags that do not have translations when running on integrated server. Format desired is tag.item.<namespace>.<path> for the translation key. Defaults to SILENCED.
|
||||||
|
#Allowed Values: SILENCED, DEV_SHORT, DEV_VERBOSE, PROD_SHORT, PROD_VERBOSE
|
||||||
|
logUntranslatedItemTagWarnings = "SILENCED"
|
||||||
|
#A config option mainly for developers. Logs out modded tags that are using the 'forge' namespace when running on integrated server. Defaults to DEV_SHORT.
|
||||||
|
#Allowed Values: SILENCED, DEV_SHORT, DEV_VERBOSE, PROD_SHORT, PROD_VERBOSE
|
||||||
|
logLegacyTagWarnings = "DEV_SHORT"
|
||||||
|
#Set this to true to enable showing debug information about attributes on an item when advanced tooltips is on.
|
||||||
|
attributeAdvancedTooltipDebugInfo = true
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
#Set this to true to remove any BlockEntity that throws an error in its update method instead of closing the server and reporting a crash log. BE WARNED THIS COULD SCREW UP EVERYTHING USE SPARINGLY WE ARE NOT RESPONSIBLE FOR DAMAGES.
|
||||||
|
removeErroringBlockEntities = false
|
||||||
|
#Set this to true to remove any Entity (Note: Does not include BlockEntities) that throws an error in its tick method instead of closing the server and reporting a crash log. BE WARNED THIS COULD SCREW UP EVERYTHING USE SPARINGLY WE ARE NOT RESPONSIBLE FOR DAMAGES.
|
||||||
|
removeErroringEntities = false
|
||||||
|
#Set this to true to check the entire entity's collision bounding box for ladders instead of just the block they are in. Causes noticeable differences in mechanics so default is vanilla behavior. Default: false.
|
||||||
|
fullBoundingBoxLadders = false
|
||||||
|
#The permission handler used by the server. Defaults to neoforge:default_handler if no such handler with that name is registered.
|
||||||
|
permissionHandler = "neoforge:default_handler"
|
||||||
|
#Set this to true to enable advertising the dedicated server to local LAN clients so that it shows up in the Multiplayer screen automatically.
|
||||||
|
advertiseDedicatedServerToLan = true
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
---- Minecraft Crash Report ----
|
||||||
|
// Hi. I'm Minecraft, and I'm a crashaholic.
|
||||||
|
|
||||||
|
Time: 2026-02-14 21:31:59
|
||||||
|
Description: Mod loading failures have occurred; consult the issue messages for more details
|
||||||
|
|
||||||
|
net.neoforged.neoforge.logging.CrashReportExtender$ModLoadingCrashException: Mod loading has failed
|
||||||
|
|
||||||
|
|
||||||
|
A detailed walkthrough of the error, its code path and all known details is as follows:
|
||||||
|
---------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
-- Head --
|
||||||
|
Thread: Render thread
|
||||||
|
Stacktrace:
|
||||||
|
at MC-BOOTSTRAP/net.neoforged.bus/net.neoforged.bus.EventBus.register(EventBus.java:135) ~[bus-8.0.5.jar%23150!/:?] {}
|
||||||
|
-- Mod loading issue for: mclaude --
|
||||||
|
Details:
|
||||||
|
Mod file: /C:/Users/dehla/Documents/MClaude/build/classes/java/main/
|
||||||
|
Failure message: MClaude (mclaude) has failed to load correctly
|
||||||
|
java.lang.IllegalArgumentException: class com.mclaude.mclaude.MClaude has no @SubscribeEvent methods, but register was called anyway.
|
||||||
|
The event bus only recognizes listener methods that have the @SubscribeEvent annotation.
|
||||||
|
|
||||||
|
Mod version: 1.0.0
|
||||||
|
Mod issues URL: <No issues URL found>
|
||||||
|
Exception message: java.lang.IllegalArgumentException: class com.mclaude.mclaude.MClaude has no @SubscribeEvent methods, but register was called anyway.
|
||||||
|
The event bus only recognizes listener methods that have the @SubscribeEvent annotation.
|
||||||
|
|
||||||
|
Stacktrace:
|
||||||
|
at MC-BOOTSTRAP/net.neoforged.bus/net.neoforged.bus.EventBus.register(EventBus.java:135) ~[bus-8.0.5.jar%23150!/:?] {}
|
||||||
|
at TRANSFORMER/mclaude@1.0.0/com.mclaude.mclaude.MClaude.<init>(MClaude.java:20) ~[%23191!/:?] {re:classloading}
|
||||||
|
at java.base/jdk.internal.reflect.DirectConstructorHandleAccessor.newInstance(DirectConstructorHandleAccessor.java:62) ~[?:?] {}
|
||||||
|
at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:502) ~[?:?] {}
|
||||||
|
at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:486) ~[?:?] {}
|
||||||
|
at MC-BOOTSTRAP/fml_loader@4.0.42/net.neoforged.fml.javafmlmod.FMLModContainer.constructMod(FMLModContainer.java:115) ~[loader-4.0.42.jar%23146!/:4.0] {}
|
||||||
|
at MC-BOOTSTRAP/fml_loader@4.0.42/net.neoforged.fml.ModLoader.lambda$constructMods$3(ModLoader.java:153) ~[loader-4.0.42.jar%23146!/:4.0] {}
|
||||||
|
at MC-BOOTSTRAP/fml_loader@4.0.42/net.neoforged.fml.ModLoader.lambda$dispatchParallelTask$7(ModLoader.java:231) ~[loader-4.0.42.jar%23146!/:4.0] {}
|
||||||
|
at java.base/java.util.concurrent.CompletableFuture.uniHandle(CompletableFuture.java:934) ~[?:?] {}
|
||||||
|
at java.base/java.util.concurrent.CompletableFuture$UniHandle.tryFire(CompletableFuture.java:911) ~[?:?] {}
|
||||||
|
at java.base/java.util.concurrent.CompletableFuture$Completion.exec(CompletableFuture.java:483) ~[?:?] {}
|
||||||
|
at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:387) ~[?:?] {}
|
||||||
|
at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1312) ~[?:?] {}
|
||||||
|
at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1843) ~[?:?] {}
|
||||||
|
at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1808) ~[?:?] {}
|
||||||
|
at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:188) ~[?:?] {}
|
||||||
|
|
||||||
|
|
||||||
|
-- System Details --
|
||||||
|
Details:
|
||||||
|
Minecraft Version: 1.21.1
|
||||||
|
Minecraft Version ID: 1.21.1
|
||||||
|
Operating System: Windows 11 (amd64) version 10.0
|
||||||
|
Java Version: 21.0.10, Eclipse Adoptium
|
||||||
|
Java VM Version: OpenJDK 64-Bit Server VM (mixed mode, sharing), Eclipse Adoptium
|
||||||
|
Memory: 150622088 bytes (143 MiB) / 599785472 bytes (572 MiB) up to 8577351680 bytes (8180 MiB)
|
||||||
|
CPUs: 12
|
||||||
|
Processor Vendor: AuthenticAMD
|
||||||
|
Processor Name: AMD Ryzen 5 5600X 6-Core Processor
|
||||||
|
Identifier: AuthenticAMD Family 25 Model 33 Stepping 0
|
||||||
|
Microarchitecture: Zen 3
|
||||||
|
Frequency (GHz): 3.69
|
||||||
|
Number of physical packages: 1
|
||||||
|
Number of physical CPUs: 6
|
||||||
|
Number of logical CPUs: 12
|
||||||
|
Graphics card #0 name: NVIDIA GeForce RTX 3070
|
||||||
|
Graphics card #0 vendor: NVIDIA
|
||||||
|
Graphics card #0 VRAM (MiB): 8192.00
|
||||||
|
Graphics card #0 deviceId: VideoController1
|
||||||
|
Graphics card #0 versionInfo: 32.0.15.9174
|
||||||
|
Memory slot #0 capacity (MiB): 16384.00
|
||||||
|
Memory slot #0 clockSpeed (GHz): 2.67
|
||||||
|
Memory slot #0 type: DDR4
|
||||||
|
Memory slot #1 capacity (MiB): 16384.00
|
||||||
|
Memory slot #1 clockSpeed (GHz): 2.67
|
||||||
|
Memory slot #1 type: DDR4
|
||||||
|
Virtual memory max (MiB): 45002.38
|
||||||
|
Virtual memory used (MiB): 29825.88
|
||||||
|
Swap memory total (MiB): 12288.00
|
||||||
|
Swap memory used (MiB): 142.94
|
||||||
|
Space in storage for jna.tmpdir (MiB): <path not set>
|
||||||
|
Space in storage for org.lwjgl.system.SharedLibraryExtractPath (MiB): <path not set>
|
||||||
|
Space in storage for io.netty.native.workdir (MiB): <path not set>
|
||||||
|
Space in storage for java.io.tmpdir (MiB): available: 412655.56, total: 953093.00
|
||||||
|
Space in storage for workdir (MiB): available: 412655.56, total: 953093.00
|
||||||
|
JVM Flags: 0 total;
|
||||||
|
ModLauncher: 11.0.5+main.901c6ea8
|
||||||
|
ModLauncher launch target: forgeclientdev
|
||||||
|
ModLauncher services:
|
||||||
|
sponge-mixin-0.15.2+mixin.0.8.7.jar mixin PLUGINSERVICE
|
||||||
|
loader-4.0.42.jar slf4jfixer PLUGINSERVICE
|
||||||
|
loader-4.0.42.jar runtime_enum_extender PLUGINSERVICE
|
||||||
|
at-modlauncher-10.0.1.jar accesstransformer PLUGINSERVICE
|
||||||
|
loader-4.0.42.jar runtimedistcleaner PLUGINSERVICE
|
||||||
|
modlauncher-11.0.5.jar mixin TRANSFORMATIONSERVICE
|
||||||
|
modlauncher-11.0.5.jar fml TRANSFORMATIONSERVICE
|
||||||
|
FML Language Providers:
|
||||||
|
javafml@4.0
|
||||||
|
lowcodefml@4.0
|
||||||
|
minecraft@4.0
|
||||||
|
Mod List:
|
||||||
|
main |MClaude |mclaude |1.0.0 |Manifest: NOSIGNATURE
|
||||||
|
neoforge-21.1.219.jar |Minecraft |minecraft |1.21.1 |Manifest: NOSIGNATURE
|
||||||
|
neoforge-21.1.219.jar |NeoForge |neoforge |21.1.219 |Manifest: NOSIGNATURE
|
||||||
|
Crash Report UUID: 680b33ca-4d58-40fe-b038-bccd517fc626
|
||||||
|
FML: 4.0.42
|
||||||
|
NeoForge: 21.1.219
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
---- Minecraft Crash Report ----
|
||||||
|
// I let you down. Sorry :(
|
||||||
|
|
||||||
|
Time: 2026-02-14 21:38:53
|
||||||
|
Description: Mod loading failures have occurred; consult the issue messages for more details
|
||||||
|
|
||||||
|
net.neoforged.neoforge.logging.CrashReportExtender$ModLoadingCrashException: Mod loading has failed
|
||||||
|
|
||||||
|
|
||||||
|
A detailed walkthrough of the error, its code path and all known details is as follows:
|
||||||
|
---------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
-- Head --
|
||||||
|
Thread: Render thread
|
||||||
|
Stacktrace:
|
||||||
|
at MC-BOOTSTRAP/net.neoforged.bus/net.neoforged.bus.EventBus.register(EventBus.java:135) ~[bus-8.0.5.jar%23150!/:?] {}
|
||||||
|
-- Mod loading issue for: clod --
|
||||||
|
Details:
|
||||||
|
Mod file: /C:/Users/dehla/Documents/MClaude/build/classes/java/main/
|
||||||
|
Failure message: Clod (clod) has failed to load correctly
|
||||||
|
java.lang.IllegalArgumentException: class com.clod.clod.Clod has no @SubscribeEvent methods, but register was called anyway.
|
||||||
|
The event bus only recognizes listener methods that have the @SubscribeEvent annotation.
|
||||||
|
|
||||||
|
Mod version: 1.0.0
|
||||||
|
Mod issues URL: <No issues URL found>
|
||||||
|
Exception message: java.lang.IllegalArgumentException: class com.clod.clod.Clod has no @SubscribeEvent methods, but register was called anyway.
|
||||||
|
The event bus only recognizes listener methods that have the @SubscribeEvent annotation.
|
||||||
|
|
||||||
|
Stacktrace:
|
||||||
|
at MC-BOOTSTRAP/net.neoforged.bus/net.neoforged.bus.EventBus.register(EventBus.java:135) ~[bus-8.0.5.jar%23150!/:?] {}
|
||||||
|
at TRANSFORMER/clod@1.0.0/com.clod.clod.Clod.<init>(Clod.java:20) ~[%23191!/:?] {re:classloading}
|
||||||
|
at java.base/jdk.internal.reflect.DirectConstructorHandleAccessor.newInstance(DirectConstructorHandleAccessor.java:62) ~[?:?] {}
|
||||||
|
at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:502) ~[?:?] {}
|
||||||
|
at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:486) ~[?:?] {}
|
||||||
|
at MC-BOOTSTRAP/fml_loader@4.0.42/net.neoforged.fml.javafmlmod.FMLModContainer.constructMod(FMLModContainer.java:115) ~[loader-4.0.42.jar%23146!/:4.0] {}
|
||||||
|
at MC-BOOTSTRAP/fml_loader@4.0.42/net.neoforged.fml.ModLoader.lambda$constructMods$3(ModLoader.java:153) ~[loader-4.0.42.jar%23146!/:4.0] {}
|
||||||
|
at MC-BOOTSTRAP/fml_loader@4.0.42/net.neoforged.fml.ModLoader.lambda$dispatchParallelTask$7(ModLoader.java:231) ~[loader-4.0.42.jar%23146!/:4.0] {}
|
||||||
|
at java.base/java.util.concurrent.CompletableFuture.uniHandle(CompletableFuture.java:934) ~[?:?] {}
|
||||||
|
at java.base/java.util.concurrent.CompletableFuture$UniHandle.tryFire(CompletableFuture.java:911) ~[?:?] {}
|
||||||
|
at java.base/java.util.concurrent.CompletableFuture$Completion.exec(CompletableFuture.java:483) ~[?:?] {}
|
||||||
|
at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:387) ~[?:?] {}
|
||||||
|
at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1312) ~[?:?] {}
|
||||||
|
at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1843) ~[?:?] {}
|
||||||
|
at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1808) ~[?:?] {}
|
||||||
|
at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:188) ~[?:?] {}
|
||||||
|
|
||||||
|
|
||||||
|
-- System Details --
|
||||||
|
Details:
|
||||||
|
Minecraft Version: 1.21.1
|
||||||
|
Minecraft Version ID: 1.21.1
|
||||||
|
Operating System: Windows 11 (amd64) version 10.0
|
||||||
|
Java Version: 21.0.10, Eclipse Adoptium
|
||||||
|
Java VM Version: OpenJDK 64-Bit Server VM (mixed mode, sharing), Eclipse Adoptium
|
||||||
|
Memory: 299025128 bytes (285 MiB) / 616562688 bytes (588 MiB) up to 8577351680 bytes (8180 MiB)
|
||||||
|
CPUs: 12
|
||||||
|
Processor Vendor: AuthenticAMD
|
||||||
|
Processor Name: AMD Ryzen 5 5600X 6-Core Processor
|
||||||
|
Identifier: AuthenticAMD Family 25 Model 33 Stepping 0
|
||||||
|
Microarchitecture: Zen 3
|
||||||
|
Frequency (GHz): 3.69
|
||||||
|
Number of physical packages: 1
|
||||||
|
Number of physical CPUs: 6
|
||||||
|
Number of logical CPUs: 12
|
||||||
|
Graphics card #0 name: NVIDIA GeForce RTX 3070
|
||||||
|
Graphics card #0 vendor: NVIDIA
|
||||||
|
Graphics card #0 VRAM (MiB): 8192.00
|
||||||
|
Graphics card #0 deviceId: VideoController1
|
||||||
|
Graphics card #0 versionInfo: 32.0.15.9174
|
||||||
|
Memory slot #0 capacity (MiB): 16384.00
|
||||||
|
Memory slot #0 clockSpeed (GHz): 2.67
|
||||||
|
Memory slot #0 type: DDR4
|
||||||
|
Memory slot #1 capacity (MiB): 16384.00
|
||||||
|
Memory slot #1 clockSpeed (GHz): 2.67
|
||||||
|
Memory slot #1 type: DDR4
|
||||||
|
Virtual memory max (MiB): 45002.38
|
||||||
|
Virtual memory used (MiB): 28338.89
|
||||||
|
Swap memory total (MiB): 12288.00
|
||||||
|
Swap memory used (MiB): 142.94
|
||||||
|
Space in storage for jna.tmpdir (MiB): <path not set>
|
||||||
|
Space in storage for org.lwjgl.system.SharedLibraryExtractPath (MiB): <path not set>
|
||||||
|
Space in storage for io.netty.native.workdir (MiB): <path not set>
|
||||||
|
Space in storage for java.io.tmpdir (MiB): available: 412657.94, total: 953093.00
|
||||||
|
Space in storage for workdir (MiB): available: 412657.94, total: 953093.00
|
||||||
|
JVM Flags: 0 total;
|
||||||
|
ModLauncher: 11.0.5+main.901c6ea8
|
||||||
|
ModLauncher launch target: forgeclientdev
|
||||||
|
ModLauncher services:
|
||||||
|
sponge-mixin-0.15.2+mixin.0.8.7.jar mixin PLUGINSERVICE
|
||||||
|
loader-4.0.42.jar slf4jfixer PLUGINSERVICE
|
||||||
|
loader-4.0.42.jar runtime_enum_extender PLUGINSERVICE
|
||||||
|
at-modlauncher-10.0.1.jar accesstransformer PLUGINSERVICE
|
||||||
|
loader-4.0.42.jar runtimedistcleaner PLUGINSERVICE
|
||||||
|
modlauncher-11.0.5.jar mixin TRANSFORMATIONSERVICE
|
||||||
|
modlauncher-11.0.5.jar fml TRANSFORMATIONSERVICE
|
||||||
|
FML Language Providers:
|
||||||
|
javafml@4.0
|
||||||
|
lowcodefml@4.0
|
||||||
|
minecraft@4.0
|
||||||
|
Mod List:
|
||||||
|
main |Clod |clod |1.0.0 |Manifest: NOSIGNATURE
|
||||||
|
neoforge-21.1.219.jar |Minecraft |minecraft |1.21.1 |Manifest: NOSIGNATURE
|
||||||
|
neoforge-21.1.219.jar |NeoForge |neoforge |21.1.219 |Manifest: NOSIGNATURE
|
||||||
|
Crash Report UUID: ce5bd7c6-34f6-4cfd-a797-480053063414
|
||||||
|
FML: 4.0.42
|
||||||
|
NeoForge: 21.1.219
|
||||||
@@ -0,0 +1,176 @@
|
|||||||
|
---- Minecraft Crash Report ----
|
||||||
|
// I bet Cylons wouldn't have this problem.
|
||||||
|
|
||||||
|
Time: 2026-02-14 21:47:31
|
||||||
|
Description: Unexpected error
|
||||||
|
|
||||||
|
java.lang.NullPointerException: Cannot invoke "net.minecraft.client.renderer.entity.EntityRenderer.shouldRender(net.minecraft.world.entity.Entity, net.minecraft.client.renderer.culling.Frustum, double, double, double)" because "entityrenderer" is null
|
||||||
|
at TRANSFORMER/minecraft@1.21.1/net.minecraft.client.renderer.entity.EntityRenderDispatcher.shouldRender(EntityRenderDispatcher.java:139) ~[neoforge-21.1.219.jar%23189!/:?] {re:classloading,pl:runtimedistcleaner:A}
|
||||||
|
at TRANSFORMER/minecraft@1.21.1/net.minecraft.client.renderer.LevelRenderer.renderLevel(LevelRenderer.java:1010) ~[neoforge-21.1.219.jar%23189!/:?] {re:classloading,pl:accesstransformer:B,pl:runtimedistcleaner:A}
|
||||||
|
at TRANSFORMER/minecraft@1.21.1/net.minecraft.client.renderer.GameRenderer.renderLevel(GameRenderer.java:1277) ~[neoforge-21.1.219.jar%23189!/:?] {re:classloading,pl:accesstransformer:B,pl:runtimedistcleaner:A}
|
||||||
|
at TRANSFORMER/minecraft@1.21.1/net.minecraft.client.renderer.GameRenderer.render(GameRenderer.java:1030) ~[neoforge-21.1.219.jar%23189!/:?] {re:classloading,pl:accesstransformer:B,pl:runtimedistcleaner:A}
|
||||||
|
at TRANSFORMER/minecraft@1.21.1/net.minecraft.client.Minecraft.runTick(Minecraft.java:1201) ~[neoforge-21.1.219.jar%23189!/:?] {re:classloading,pl:runtimedistcleaner:A}
|
||||||
|
at TRANSFORMER/minecraft@1.21.1/net.minecraft.client.Minecraft.run(Minecraft.java:813) ~[neoforge-21.1.219.jar%23189!/:?] {re:classloading,pl:runtimedistcleaner:A}
|
||||||
|
at TRANSFORMER/minecraft@1.21.1/net.minecraft.client.main.Main.main(Main.java:230) ~[neoforge-21.1.219.jar%23189!/:?] {re:classloading,pl:runtimedistcleaner:A}
|
||||||
|
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) ~[?:?] {}
|
||||||
|
at java.base/java.lang.reflect.Method.invoke(Method.java:580) ~[?:?] {}
|
||||||
|
at MC-BOOTSTRAP/fml_loader@4.0.42/net.neoforged.fml.loading.targets.CommonLaunchHandler.runTarget(CommonLaunchHandler.java:136) ~[loader-4.0.42.jar%23146!/:4.0] {}
|
||||||
|
at MC-BOOTSTRAP/fml_loader@4.0.42/net.neoforged.fml.loading.targets.CommonLaunchHandler.clientService(CommonLaunchHandler.java:124) ~[loader-4.0.42.jar%23146!/:4.0] {}
|
||||||
|
at MC-BOOTSTRAP/fml_loader@4.0.42/net.neoforged.fml.loading.targets.NeoForgeClientDevLaunchHandler.runService(NeoForgeClientDevLaunchHandler.java:23) ~[loader-4.0.42.jar%23146!/:4.0] {}
|
||||||
|
at MC-BOOTSTRAP/fml_loader@4.0.42/net.neoforged.fml.loading.targets.CommonLaunchHandler.lambda$launchService$4(CommonLaunchHandler.java:118) ~[loader-4.0.42.jar%23146!/:4.0] {}
|
||||||
|
at MC-BOOTSTRAP/cpw.mods.modlauncher@11.0.5/cpw.mods.modlauncher.LaunchServiceHandlerDecorator.launch(LaunchServiceHandlerDecorator.java:30) [modlauncher-11.0.5.jar%23128!/:?] {}
|
||||||
|
at MC-BOOTSTRAP/cpw.mods.modlauncher@11.0.5/cpw.mods.modlauncher.LaunchServiceHandler.launch(LaunchServiceHandler.java:53) [modlauncher-11.0.5.jar%23128!/:?] {}
|
||||||
|
at MC-BOOTSTRAP/cpw.mods.modlauncher@11.0.5/cpw.mods.modlauncher.LaunchServiceHandler.launch(LaunchServiceHandler.java:71) [modlauncher-11.0.5.jar%23128!/:?] {}
|
||||||
|
at MC-BOOTSTRAP/cpw.mods.modlauncher@11.0.5/cpw.mods.modlauncher.Launcher.run(Launcher.java:103) [modlauncher-11.0.5.jar%23128!/:?] {}
|
||||||
|
at MC-BOOTSTRAP/cpw.mods.modlauncher@11.0.5/cpw.mods.modlauncher.Launcher.main(Launcher.java:74) [modlauncher-11.0.5.jar%23128!/:?] {}
|
||||||
|
at MC-BOOTSTRAP/cpw.mods.modlauncher@11.0.5/cpw.mods.modlauncher.BootstrapLaunchConsumer.accept(BootstrapLaunchConsumer.java:26) [modlauncher-11.0.5.jar%23128!/:?] {}
|
||||||
|
at MC-BOOTSTRAP/cpw.mods.modlauncher@11.0.5/cpw.mods.modlauncher.BootstrapLaunchConsumer.accept(BootstrapLaunchConsumer.java:23) [modlauncher-11.0.5.jar%23128!/:?] {}
|
||||||
|
at cpw.mods.bootstraplauncher@2.0.2/cpw.mods.bootstraplauncher.BootstrapLauncher.run(BootstrapLauncher.java:210) [bootstraplauncher-2.0.2.jar:?] {}
|
||||||
|
at cpw.mods.bootstraplauncher@2.0.2/cpw.mods.bootstraplauncher.BootstrapLauncher.main(BootstrapLauncher.java:69) [bootstraplauncher-2.0.2.jar:?] {}
|
||||||
|
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) ~[?:?] {}
|
||||||
|
at java.base/java.lang.reflect.Method.invoke(Method.java:580) ~[?:?] {}
|
||||||
|
at net.neoforged.devlaunch.Main.main(Main.java:55) [DevLaunch-1.0.1.jar:?] {}
|
||||||
|
|
||||||
|
|
||||||
|
A detailed walkthrough of the error, its code path and all known details is as follows:
|
||||||
|
---------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
-- Head --
|
||||||
|
Thread: Render thread
|
||||||
|
Stacktrace:
|
||||||
|
at TRANSFORMER/minecraft@1.21.1/net.minecraft.client.renderer.entity.EntityRenderDispatcher.shouldRender(EntityRenderDispatcher.java:139) ~[neoforge-21.1.219.jar%23189!/:?] {re:classloading,pl:runtimedistcleaner:A}
|
||||||
|
at TRANSFORMER/minecraft@1.21.1/net.minecraft.client.renderer.LevelRenderer.renderLevel(LevelRenderer.java:1010) ~[neoforge-21.1.219.jar%23189!/:?] {re:classloading,pl:accesstransformer:B,pl:runtimedistcleaner:A}
|
||||||
|
at TRANSFORMER/minecraft@1.21.1/net.minecraft.client.renderer.GameRenderer.renderLevel(GameRenderer.java:1277) ~[neoforge-21.1.219.jar%23189!/:?] {re:classloading,pl:accesstransformer:B,pl:runtimedistcleaner:A}
|
||||||
|
-- Uptime --
|
||||||
|
Details:
|
||||||
|
JVM uptime: 49.303s
|
||||||
|
Wall uptime: 40.341s
|
||||||
|
High-res time: 47.561s
|
||||||
|
Client ticks: 766 ticks / 38.300s
|
||||||
|
Stacktrace:
|
||||||
|
at TRANSFORMER/minecraft@1.21.1/net.minecraft.client.Minecraft.fillReport(Minecraft.java:2409) ~[neoforge-21.1.219.jar%23189!/:?] {re:classloading,pl:runtimedistcleaner:A}
|
||||||
|
at TRANSFORMER/minecraft@1.21.1/net.minecraft.client.Minecraft.emergencySaveAndCrash(Minecraft.java:874) ~[neoforge-21.1.219.jar%23189!/:?] {re:classloading,pl:runtimedistcleaner:A}
|
||||||
|
at TRANSFORMER/minecraft@1.21.1/net.minecraft.client.Minecraft.run(Minecraft.java:834) ~[neoforge-21.1.219.jar%23189!/:?] {re:classloading,pl:runtimedistcleaner:A}
|
||||||
|
at TRANSFORMER/minecraft@1.21.1/net.minecraft.client.main.Main.main(Main.java:230) ~[neoforge-21.1.219.jar%23189!/:?] {re:classloading,pl:runtimedistcleaner:A}
|
||||||
|
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) ~[?:?] {}
|
||||||
|
at java.base/java.lang.reflect.Method.invoke(Method.java:580) ~[?:?] {}
|
||||||
|
at MC-BOOTSTRAP/fml_loader@4.0.42/net.neoforged.fml.loading.targets.CommonLaunchHandler.runTarget(CommonLaunchHandler.java:136) ~[loader-4.0.42.jar%23146!/:4.0] {}
|
||||||
|
at MC-BOOTSTRAP/fml_loader@4.0.42/net.neoforged.fml.loading.targets.CommonLaunchHandler.clientService(CommonLaunchHandler.java:124) ~[loader-4.0.42.jar%23146!/:4.0] {}
|
||||||
|
at MC-BOOTSTRAP/fml_loader@4.0.42/net.neoforged.fml.loading.targets.NeoForgeClientDevLaunchHandler.runService(NeoForgeClientDevLaunchHandler.java:23) ~[loader-4.0.42.jar%23146!/:4.0] {}
|
||||||
|
at MC-BOOTSTRAP/fml_loader@4.0.42/net.neoforged.fml.loading.targets.CommonLaunchHandler.lambda$launchService$4(CommonLaunchHandler.java:118) ~[loader-4.0.42.jar%23146!/:4.0] {}
|
||||||
|
at MC-BOOTSTRAP/cpw.mods.modlauncher@11.0.5/cpw.mods.modlauncher.LaunchServiceHandlerDecorator.launch(LaunchServiceHandlerDecorator.java:30) [modlauncher-11.0.5.jar%23128!/:?] {}
|
||||||
|
at MC-BOOTSTRAP/cpw.mods.modlauncher@11.0.5/cpw.mods.modlauncher.LaunchServiceHandler.launch(LaunchServiceHandler.java:53) [modlauncher-11.0.5.jar%23128!/:?] {}
|
||||||
|
at MC-BOOTSTRAP/cpw.mods.modlauncher@11.0.5/cpw.mods.modlauncher.LaunchServiceHandler.launch(LaunchServiceHandler.java:71) [modlauncher-11.0.5.jar%23128!/:?] {}
|
||||||
|
at MC-BOOTSTRAP/cpw.mods.modlauncher@11.0.5/cpw.mods.modlauncher.Launcher.run(Launcher.java:103) [modlauncher-11.0.5.jar%23128!/:?] {}
|
||||||
|
at MC-BOOTSTRAP/cpw.mods.modlauncher@11.0.5/cpw.mods.modlauncher.Launcher.main(Launcher.java:74) [modlauncher-11.0.5.jar%23128!/:?] {}
|
||||||
|
at MC-BOOTSTRAP/cpw.mods.modlauncher@11.0.5/cpw.mods.modlauncher.BootstrapLaunchConsumer.accept(BootstrapLaunchConsumer.java:26) [modlauncher-11.0.5.jar%23128!/:?] {}
|
||||||
|
at MC-BOOTSTRAP/cpw.mods.modlauncher@11.0.5/cpw.mods.modlauncher.BootstrapLaunchConsumer.accept(BootstrapLaunchConsumer.java:23) [modlauncher-11.0.5.jar%23128!/:?] {}
|
||||||
|
at cpw.mods.bootstraplauncher@2.0.2/cpw.mods.bootstraplauncher.BootstrapLauncher.run(BootstrapLauncher.java:210) [bootstraplauncher-2.0.2.jar:?] {}
|
||||||
|
at cpw.mods.bootstraplauncher@2.0.2/cpw.mods.bootstraplauncher.BootstrapLauncher.main(BootstrapLauncher.java:69) [bootstraplauncher-2.0.2.jar:?] {}
|
||||||
|
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) ~[?:?] {}
|
||||||
|
at java.base/java.lang.reflect.Method.invoke(Method.java:580) ~[?:?] {}
|
||||||
|
at net.neoforged.devlaunch.Main.main(Main.java:55) [DevLaunch-1.0.1.jar:?] {}
|
||||||
|
|
||||||
|
|
||||||
|
-- Affected level --
|
||||||
|
Details:
|
||||||
|
All players: 1 total; [LocalPlayer['Dev'/1, l='ClientLevel', x=0.50, y=-60.00, z=-0.50]]
|
||||||
|
Chunk stats: 961, 609
|
||||||
|
Level dimension: minecraft:overworld
|
||||||
|
Level spawn location: World: (0,-60,0), Section: (at 0,4,0 in 0,-4,0; chunk contains blocks 0,-64,0 to 15,319,15), Region: (0,0; contains chunks 0,0 to 31,31, blocks 0,-64,0 to 511,319,511)
|
||||||
|
Level time: 122 game time, 122 day time
|
||||||
|
Server brand: neoforge
|
||||||
|
Server type: Integrated singleplayer server
|
||||||
|
Tracked entity count: 2
|
||||||
|
|
||||||
|
-- Last reload --
|
||||||
|
Details:
|
||||||
|
Reload number: 1
|
||||||
|
Reload reason: initial
|
||||||
|
Finished: Yes
|
||||||
|
Packs: vanilla, mod_resources, mod/clod, mod/neoforge
|
||||||
|
|
||||||
|
-- System Details --
|
||||||
|
Details:
|
||||||
|
Minecraft Version: 1.21.1
|
||||||
|
Minecraft Version ID: 1.21.1
|
||||||
|
Operating System: Windows 11 (amd64) version 10.0
|
||||||
|
Java Version: 21.0.10, Eclipse Adoptium
|
||||||
|
Java VM Version: OpenJDK 64-Bit Server VM (mixed mode, sharing), Eclipse Adoptium
|
||||||
|
Memory: 153765056 bytes (146 MiB) / 830472192 bytes (792 MiB) up to 8577351680 bytes (8180 MiB)
|
||||||
|
CPUs: 12
|
||||||
|
Processor Vendor: AuthenticAMD
|
||||||
|
Processor Name: AMD Ryzen 5 5600X 6-Core Processor
|
||||||
|
Identifier: AuthenticAMD Family 25 Model 33 Stepping 0
|
||||||
|
Microarchitecture: Zen 3
|
||||||
|
Frequency (GHz): 3.69
|
||||||
|
Number of physical packages: 1
|
||||||
|
Number of physical CPUs: 6
|
||||||
|
Number of logical CPUs: 12
|
||||||
|
Graphics card #0 name: NVIDIA GeForce RTX 3070
|
||||||
|
Graphics card #0 vendor: NVIDIA
|
||||||
|
Graphics card #0 VRAM (MiB): 8192.00
|
||||||
|
Graphics card #0 deviceId: VideoController1
|
||||||
|
Graphics card #0 versionInfo: 32.0.15.9174
|
||||||
|
Memory slot #0 capacity (MiB): 16384.00
|
||||||
|
Memory slot #0 clockSpeed (GHz): 2.67
|
||||||
|
Memory slot #0 type: DDR4
|
||||||
|
Memory slot #1 capacity (MiB): 16384.00
|
||||||
|
Memory slot #1 clockSpeed (GHz): 2.67
|
||||||
|
Memory slot #1 type: DDR4
|
||||||
|
Virtual memory max (MiB): 45002.38
|
||||||
|
Virtual memory used (MiB): 29142.02
|
||||||
|
Swap memory total (MiB): 12288.00
|
||||||
|
Swap memory used (MiB): 146.80
|
||||||
|
Space in storage for jna.tmpdir (MiB): <path not set>
|
||||||
|
Space in storage for org.lwjgl.system.SharedLibraryExtractPath (MiB): <path not set>
|
||||||
|
Space in storage for io.netty.native.workdir (MiB): <path not set>
|
||||||
|
Space in storage for java.io.tmpdir (MiB): available: 412526.78, total: 953093.00
|
||||||
|
Space in storage for workdir (MiB): available: 412526.78, total: 953093.00
|
||||||
|
JVM Flags: 0 total;
|
||||||
|
Launched Version: 21.1.219
|
||||||
|
Backend library: LWJGL version 3.3.3+5
|
||||||
|
Backend API: NVIDIA GeForce RTX 3070/PCIe/SSE2 GL version 4.6.0 NVIDIA 591.74, NVIDIA Corporation
|
||||||
|
Window size: 2560x1369
|
||||||
|
GFLW Platform: win32
|
||||||
|
GL Caps: Using framebuffer using OpenGL 3.2
|
||||||
|
GL debug messages:
|
||||||
|
Is Modded: Definitely; Client brand changed to 'neoforge'; Server brand changed to 'neoforge'
|
||||||
|
Universe: 400921fb54442d18
|
||||||
|
Type: Integrated Server (map_client.txt)
|
||||||
|
Graphics mode: fancy
|
||||||
|
Render Distance: 12/12 chunks
|
||||||
|
Resource Packs: vanilla, mod_resources, mod/clod, mod/neoforge
|
||||||
|
Current Language: en_us
|
||||||
|
Locale: en_GB
|
||||||
|
System encoding: Cp1252
|
||||||
|
File encoding: UTF-8
|
||||||
|
CPU: 12x AMD Ryzen 5 5600X 6-Core Processor
|
||||||
|
Server Running: true
|
||||||
|
Player Count: 1 / 8; [ServerPlayer['Dev'/1, l='ServerLevel[New World]', x=0.50, y=-60.00, z=-0.50]]
|
||||||
|
Active Data Packs: vanilla, mod_data, mod/clod (incompatible), mod/neoforge
|
||||||
|
Available Data Packs: bundle, trade_rebalance, vanilla, mod/clod (incompatible), mod/neoforge, mod_data
|
||||||
|
Enabled Feature Flags: minecraft:vanilla
|
||||||
|
World Generation: Stable
|
||||||
|
World Seed: 364119556846425357
|
||||||
|
ModLauncher: 11.0.5+main.901c6ea8
|
||||||
|
ModLauncher launch target: forgeclientdev
|
||||||
|
ModLauncher services:
|
||||||
|
sponge-mixin-0.15.2+mixin.0.8.7.jar mixin PLUGINSERVICE
|
||||||
|
loader-4.0.42.jar slf4jfixer PLUGINSERVICE
|
||||||
|
loader-4.0.42.jar runtime_enum_extender PLUGINSERVICE
|
||||||
|
at-modlauncher-10.0.1.jar accesstransformer PLUGINSERVICE
|
||||||
|
loader-4.0.42.jar runtimedistcleaner PLUGINSERVICE
|
||||||
|
modlauncher-11.0.5.jar mixin TRANSFORMATIONSERVICE
|
||||||
|
modlauncher-11.0.5.jar fml TRANSFORMATIONSERVICE
|
||||||
|
FML Language Providers:
|
||||||
|
javafml@4.0
|
||||||
|
lowcodefml@4.0
|
||||||
|
minecraft@4.0
|
||||||
|
Mod List:
|
||||||
|
main |Clod |clod |1.0.0 |Manifest: NOSIGNATURE
|
||||||
|
neoforge-21.1.219.jar |Minecraft |minecraft |1.21.1 |Manifest: NOSIGNATURE
|
||||||
|
neoforge-21.1.219.jar |NeoForge |neoforge |21.1.219 |Manifest: NOSIGNATURE
|
||||||
|
Crash Report UUID: d7d6e879-f216-40b8-9be9-2591731046c2
|
||||||
|
FML: 4.0.42
|
||||||
|
NeoForge: 21.1.219
|
||||||
+140
@@ -0,0 +1,140 @@
|
|||||||
|
version:3955
|
||||||
|
ao:true
|
||||||
|
biomeBlendRadius:2
|
||||||
|
enableVsync:true
|
||||||
|
entityDistanceScaling:1.0
|
||||||
|
entityShadows:true
|
||||||
|
forceUnicodeFont:false
|
||||||
|
japaneseGlyphVariants:false
|
||||||
|
fov:0.0
|
||||||
|
fovEffectScale:1.0
|
||||||
|
darknessEffectScale:1.0
|
||||||
|
glintSpeed:0.5
|
||||||
|
glintStrength:0.75
|
||||||
|
prioritizeChunkUpdates:0
|
||||||
|
fullscreen:false
|
||||||
|
gamma:0.5
|
||||||
|
graphicsMode:1
|
||||||
|
guiScale:2
|
||||||
|
maxFps:120
|
||||||
|
mipmapLevels:4
|
||||||
|
narrator:0
|
||||||
|
particles:0
|
||||||
|
reducedDebugInfo:false
|
||||||
|
renderClouds:"true"
|
||||||
|
renderDistance:12
|
||||||
|
simulationDistance:12
|
||||||
|
screenEffectScale:1.0
|
||||||
|
soundDevice:""
|
||||||
|
autoJump:false
|
||||||
|
operatorItemsTab:false
|
||||||
|
autoSuggestions:true
|
||||||
|
chatColors:true
|
||||||
|
chatLinks:true
|
||||||
|
chatLinksPrompt:true
|
||||||
|
discrete_mouse_scroll:false
|
||||||
|
invertYMouse:false
|
||||||
|
realmsNotifications:true
|
||||||
|
showSubtitles:false
|
||||||
|
directionalAudio:false
|
||||||
|
touchscreen:false
|
||||||
|
bobView:true
|
||||||
|
toggleCrouch:false
|
||||||
|
toggleSprint:false
|
||||||
|
darkMojangStudiosBackground:false
|
||||||
|
hideLightningFlashes:false
|
||||||
|
hideSplashTexts:false
|
||||||
|
mouseSensitivity:0.5
|
||||||
|
damageTiltStrength:1.0
|
||||||
|
highContrast:false
|
||||||
|
narratorHotkey:true
|
||||||
|
resourcePacks:[]
|
||||||
|
incompatibleResourcePacks:[]
|
||||||
|
lastServer:
|
||||||
|
lang:en_us
|
||||||
|
chatVisibility:0
|
||||||
|
chatOpacity:1.0
|
||||||
|
chatLineSpacing:0.0
|
||||||
|
textBackgroundOpacity:0.5
|
||||||
|
backgroundForChatOnly:true
|
||||||
|
hideServerAddress:false
|
||||||
|
advancedItemTooltips:false
|
||||||
|
pauseOnLostFocus:true
|
||||||
|
overrideWidth:0
|
||||||
|
overrideHeight:0
|
||||||
|
chatHeightFocused:1.0
|
||||||
|
chatDelay:0.0
|
||||||
|
chatHeightUnfocused:0.4375
|
||||||
|
chatScale:1.0
|
||||||
|
chatWidth:1.0
|
||||||
|
notificationDisplayTime:1.0
|
||||||
|
useNativeTransport:true
|
||||||
|
mainHand:"right"
|
||||||
|
attackIndicator:1
|
||||||
|
tutorialStep:none
|
||||||
|
mouseWheelSensitivity:1.0
|
||||||
|
rawMouseInput:true
|
||||||
|
glDebugVerbosity:1
|
||||||
|
skipMultiplayerWarning:false
|
||||||
|
hideMatchedNames:true
|
||||||
|
joinedFirstServer:false
|
||||||
|
hideBundleTutorial:false
|
||||||
|
syncChunkWrites:true
|
||||||
|
showAutosaveIndicator:true
|
||||||
|
allowServerListing:true
|
||||||
|
onlyShowSecureChat:false
|
||||||
|
panoramaScrollSpeed:1.0
|
||||||
|
telemetryOptInExtra:false
|
||||||
|
onboardAccessibility:false
|
||||||
|
menuBackgroundBlurriness:5
|
||||||
|
key_key.attack:key.mouse.left
|
||||||
|
key_key.use:key.mouse.right
|
||||||
|
key_key.forward:key.keyboard.w
|
||||||
|
key_key.left:key.keyboard.a
|
||||||
|
key_key.back:key.keyboard.s
|
||||||
|
key_key.right:key.keyboard.d
|
||||||
|
key_key.jump:key.keyboard.space
|
||||||
|
key_key.sneak:key.keyboard.left.shift
|
||||||
|
key_key.sprint:key.keyboard.left.control
|
||||||
|
key_key.drop:key.keyboard.q
|
||||||
|
key_key.inventory:key.keyboard.e
|
||||||
|
key_key.chat:key.keyboard.t
|
||||||
|
key_key.playerlist:key.keyboard.tab
|
||||||
|
key_key.pickItem:key.mouse.middle
|
||||||
|
key_key.command:key.keyboard.slash
|
||||||
|
key_key.socialInteractions:key.keyboard.p
|
||||||
|
key_key.screenshot:key.keyboard.f2
|
||||||
|
key_key.togglePerspective:key.keyboard.f5
|
||||||
|
key_key.smoothCamera:key.keyboard.unknown
|
||||||
|
key_key.fullscreen:key.keyboard.f11
|
||||||
|
key_key.spectatorOutlines:key.keyboard.unknown
|
||||||
|
key_key.swapOffhand:key.keyboard.f
|
||||||
|
key_key.saveToolbarActivator:key.keyboard.c
|
||||||
|
key_key.loadToolbarActivator:key.keyboard.x
|
||||||
|
key_key.advancements:key.keyboard.l
|
||||||
|
key_key.hotbar.1:key.keyboard.1
|
||||||
|
key_key.hotbar.2:key.keyboard.2
|
||||||
|
key_key.hotbar.3:key.keyboard.3
|
||||||
|
key_key.hotbar.4:key.keyboard.4
|
||||||
|
key_key.hotbar.5:key.keyboard.5
|
||||||
|
key_key.hotbar.6:key.keyboard.6
|
||||||
|
key_key.hotbar.7:key.keyboard.7
|
||||||
|
key_key.hotbar.8:key.keyboard.8
|
||||||
|
key_key.hotbar.9:key.keyboard.9
|
||||||
|
soundCategory_master:1.0
|
||||||
|
soundCategory_music:1.0
|
||||||
|
soundCategory_record:1.0
|
||||||
|
soundCategory_weather:1.0
|
||||||
|
soundCategory_block:1.0
|
||||||
|
soundCategory_hostile:1.0
|
||||||
|
soundCategory_neutral:1.0
|
||||||
|
soundCategory_player:1.0
|
||||||
|
soundCategory_ambient:1.0
|
||||||
|
soundCategory_voice:1.0
|
||||||
|
modelPart_cape:true
|
||||||
|
modelPart_jacket:true
|
||||||
|
modelPart_left_sleeve:true
|
||||||
|
modelPart_right_sleeve:true
|
||||||
|
modelPart_left_pants_leg:true
|
||||||
|
modelPart_right_pants_leg:true
|
||||||
|
modelPart_hat:true
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,171 @@
|
|||||||
|
{
|
||||||
|
"minecraft:recipes/decorations/crafting_table": {
|
||||||
|
"criteria": {
|
||||||
|
"unlock_right_away": "2026-02-14 21:47:24 +0100"
|
||||||
|
},
|
||||||
|
"done": true
|
||||||
|
},
|
||||||
|
"minecraft:adventure/adventuring_time": {
|
||||||
|
"criteria": {
|
||||||
|
"minecraft:plains": "2026-02-14 21:47:25 +0100"
|
||||||
|
},
|
||||||
|
"done": false
|
||||||
|
},
|
||||||
|
"minecraft:recipes/combat/leather_helmet": {
|
||||||
|
"criteria": {
|
||||||
|
"has_leather": "2026-02-14 23:13:36 +0100"
|
||||||
|
},
|
||||||
|
"done": true
|
||||||
|
},
|
||||||
|
"minecraft:recipes/building_blocks/polished_blackstone_brick_slab": {
|
||||||
|
"criteria": {
|
||||||
|
"has_polished_blackstone_bricks": "2026-02-15 00:12:31 +0100"
|
||||||
|
},
|
||||||
|
"done": true
|
||||||
|
},
|
||||||
|
"minecraft:recipes/transportation/mangrove_boat": {
|
||||||
|
"criteria": {
|
||||||
|
"in_water": "2026-02-15 00:24:16 +0100"
|
||||||
|
},
|
||||||
|
"done": true
|
||||||
|
},
|
||||||
|
"minecraft:recipes/combat/leather_leggings": {
|
||||||
|
"criteria": {
|
||||||
|
"has_leather": "2026-02-14 23:13:36 +0100"
|
||||||
|
},
|
||||||
|
"done": true
|
||||||
|
},
|
||||||
|
"minecraft:recipes/building_blocks/polished_blackstone_brick_stairs": {
|
||||||
|
"criteria": {
|
||||||
|
"has_polished_blackstone_bricks": "2026-02-15 00:12:31 +0100"
|
||||||
|
},
|
||||||
|
"done": true
|
||||||
|
},
|
||||||
|
"minecraft:recipes/food/cooked_beef_from_smoking": {
|
||||||
|
"criteria": {
|
||||||
|
"has_beef": "2026-02-14 23:12:16 +0100"
|
||||||
|
},
|
||||||
|
"done": true
|
||||||
|
},
|
||||||
|
"minecraft:recipes/decorations/item_frame": {
|
||||||
|
"criteria": {
|
||||||
|
"has_leather": "2026-02-14 23:13:36 +0100"
|
||||||
|
},
|
||||||
|
"done": true
|
||||||
|
},
|
||||||
|
"minecraft:recipes/combat/leather_chestplate": {
|
||||||
|
"criteria": {
|
||||||
|
"has_leather": "2026-02-14 23:13:36 +0100"
|
||||||
|
},
|
||||||
|
"done": true
|
||||||
|
},
|
||||||
|
"minecraft:recipes/decorations/polished_blackstone_brick_wall_from_polished_blackstone_bricks_stonecutting": {
|
||||||
|
"criteria": {
|
||||||
|
"has_polished_blackstone_bricks": "2026-02-15 00:12:31 +0100"
|
||||||
|
},
|
||||||
|
"done": true
|
||||||
|
},
|
||||||
|
"minecraft:recipes/building_blocks/cracked_polished_blackstone_bricks": {
|
||||||
|
"criteria": {
|
||||||
|
"has_polished_blackstone_bricks": "2026-02-15 00:12:31 +0100"
|
||||||
|
},
|
||||||
|
"done": true
|
||||||
|
},
|
||||||
|
"minecraft:recipes/building_blocks/polished_blackstone_brick_slab_from_polished_blackstone_bricks_stonecutting": {
|
||||||
|
"criteria": {
|
||||||
|
"has_polished_blackstone_bricks": "2026-02-15 00:12:31 +0100"
|
||||||
|
},
|
||||||
|
"done": true
|
||||||
|
},
|
||||||
|
"minecraft:recipes/brewing/cauldron": {
|
||||||
|
"criteria": {
|
||||||
|
"has_water_bucket": "2026-02-15 00:19:24 +0100"
|
||||||
|
},
|
||||||
|
"done": true
|
||||||
|
},
|
||||||
|
"minecraft:recipes/transportation/acacia_boat": {
|
||||||
|
"criteria": {
|
||||||
|
"in_water": "2026-02-15 00:24:16 +0100"
|
||||||
|
},
|
||||||
|
"done": true
|
||||||
|
},
|
||||||
|
"minecraft:recipes/transportation/cherry_boat": {
|
||||||
|
"criteria": {
|
||||||
|
"in_water": "2026-02-15 00:24:16 +0100"
|
||||||
|
},
|
||||||
|
"done": true
|
||||||
|
},
|
||||||
|
"minecraft:recipes/decorations/polished_blackstone_brick_wall": {
|
||||||
|
"criteria": {
|
||||||
|
"has_polished_blackstone_bricks": "2026-02-15 00:12:31 +0100"
|
||||||
|
},
|
||||||
|
"done": true
|
||||||
|
},
|
||||||
|
"minecraft:recipes/transportation/bamboo_raft": {
|
||||||
|
"criteria": {
|
||||||
|
"in_water": "2026-02-15 00:24:16 +0100"
|
||||||
|
},
|
||||||
|
"done": true
|
||||||
|
},
|
||||||
|
"minecraft:recipes/combat/leather_boots": {
|
||||||
|
"criteria": {
|
||||||
|
"has_leather": "2026-02-14 23:13:36 +0100"
|
||||||
|
},
|
||||||
|
"done": true
|
||||||
|
},
|
||||||
|
"minecraft:recipes/transportation/spruce_boat": {
|
||||||
|
"criteria": {
|
||||||
|
"in_water": "2026-02-15 00:24:16 +0100"
|
||||||
|
},
|
||||||
|
"done": true
|
||||||
|
},
|
||||||
|
"minecraft:recipes/misc/leather_horse_armor": {
|
||||||
|
"criteria": {
|
||||||
|
"has_leather": "2026-02-14 23:13:36 +0100"
|
||||||
|
},
|
||||||
|
"done": true
|
||||||
|
},
|
||||||
|
"minecraft:recipes/transportation/birch_boat": {
|
||||||
|
"criteria": {
|
||||||
|
"in_water": "2026-02-15 00:24:16 +0100"
|
||||||
|
},
|
||||||
|
"done": true
|
||||||
|
},
|
||||||
|
"minecraft:recipes/building_blocks/polished_blackstone_brick_stairs_from_polished_blackstone_bricks_stonecutting": {
|
||||||
|
"criteria": {
|
||||||
|
"has_polished_blackstone_bricks": "2026-02-15 00:12:31 +0100"
|
||||||
|
},
|
||||||
|
"done": true
|
||||||
|
},
|
||||||
|
"minecraft:recipes/transportation/oak_boat": {
|
||||||
|
"criteria": {
|
||||||
|
"in_water": "2026-02-15 00:24:16 +0100"
|
||||||
|
},
|
||||||
|
"done": true
|
||||||
|
},
|
||||||
|
"minecraft:recipes/food/cooked_beef": {
|
||||||
|
"criteria": {
|
||||||
|
"has_beef": "2026-02-14 23:12:16 +0100"
|
||||||
|
},
|
||||||
|
"done": true
|
||||||
|
},
|
||||||
|
"minecraft:recipes/transportation/jungle_boat": {
|
||||||
|
"criteria": {
|
||||||
|
"in_water": "2026-02-15 00:24:16 +0100"
|
||||||
|
},
|
||||||
|
"done": true
|
||||||
|
},
|
||||||
|
"minecraft:recipes/transportation/dark_oak_boat": {
|
||||||
|
"criteria": {
|
||||||
|
"in_water": "2026-02-15 00:24:16 +0100"
|
||||||
|
},
|
||||||
|
"done": true
|
||||||
|
},
|
||||||
|
"minecraft:recipes/food/cooked_beef_from_campfire_cooking": {
|
||||||
|
"criteria": {
|
||||||
|
"has_beef": "2026-02-14 23:12:16 +0100"
|
||||||
|
},
|
||||||
|
"done": true
|
||||||
|
},
|
||||||
|
"DataVersion": 3955
|
||||||
|
}
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 5.7 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,3 @@
|
|||||||
|
Any server configs put in this folder will override the corresponding server config from <instance path>/config/<config path>.
|
||||||
|
If the config being transferred is in a subfolder of the base config folder make sure to include that folder here in the path to the file you are overwriting.
|
||||||
|
For example if you are overwriting a config with the path <instance path>/config/ExampleMod/config-server.toml, you would need to put it in serverconfig/ExampleMod/config-server.toml
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
☃
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"stats":{"minecraft:custom":{"minecraft:time_since_rest":199,"minecraft:open_chest":4,"minecraft:crouch_one_cm":237,"minecraft:sprint_one_cm":8185,"minecraft:play_time":91417,"minecraft:deaths":6,"minecraft:damage_taken":120,"minecraft:walk_one_cm":156252,"minecraft:sneak_time":1399,"minecraft:jump":24,"minecraft:damage_dealt":110,"minecraft:leave_game":4,"minecraft:time_since_death":159,"minecraft:total_world_time":131342,"minecraft:fall_one_cm":1455,"minecraft:fly_one_cm":650359},"minecraft:picked_up":{"minecraft:leather":2,"minecraft:beef":1},"minecraft:used":{"minecraft:polished_blackstone_bricks":2,"minecraft:water_bucket":4,"minecraft:iron_bars":7,"minecraft:villager_spawn_egg":4,"minecraft:red_bed":5,"minecraft:grass_block":1,"minecraft:zombie_spawn_egg":4}},"DataVersion":3955}
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 241 KiB |
@@ -0,0 +1 @@
|
|||||||
|
[{"name":"Dev","uuid":"380df991-f603-344c-a090-369bad2a924a","expiresOn":"2026-03-14 22:39:22 +0100"}]
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"380df991-f603-344c-a090-369bad2a924a": "Dev"
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
pluginManagement {
|
||||||
|
repositories {
|
||||||
|
mavenLocal()
|
||||||
|
gradlePluginPortal()
|
||||||
|
maven { url = 'https://maven.neoforged.net/releases' }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
id 'org.gradle.toolchains.foojay-resolver-convention' version '0.8.0'
|
||||||
|
}
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
package com.clod.clod;
|
||||||
|
|
||||||
|
import com.clod.clod.client.ClodEntityRenderer;
|
||||||
|
import com.clod.clod.client.ClodModel;
|
||||||
|
import com.clod.clod.command.ClodCommands;
|
||||||
|
import com.clod.clod.entity.ClodEntity;
|
||||||
|
import com.clod.clod.init.ModEntities;
|
||||||
|
import com.clod.clod.server.ClodHttpServer;
|
||||||
|
import com.mojang.logging.LogUtils;
|
||||||
|
import net.neoforged.api.distmarker.Dist;
|
||||||
|
import net.neoforged.bus.api.IEventBus;
|
||||||
|
import net.neoforged.bus.api.SubscribeEvent;
|
||||||
|
import net.neoforged.fml.ModContainer;
|
||||||
|
import net.neoforged.fml.common.EventBusSubscriber;
|
||||||
|
import net.neoforged.fml.common.Mod;
|
||||||
|
import net.neoforged.fml.event.lifecycle.FMLCommonSetupEvent;
|
||||||
|
import net.neoforged.neoforge.client.event.EntityRenderersEvent;
|
||||||
|
import net.neoforged.neoforge.common.NeoForge;
|
||||||
|
import net.neoforged.neoforge.event.RegisterCommandsEvent;
|
||||||
|
import net.neoforged.neoforge.event.ServerChatEvent;
|
||||||
|
import net.neoforged.neoforge.event.entity.EntityAttributeCreationEvent;
|
||||||
|
import net.neoforged.neoforge.event.server.ServerStartedEvent;
|
||||||
|
import net.neoforged.neoforge.event.server.ServerStoppingEvent;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
|
||||||
|
@Mod(Clod.MODID)
|
||||||
|
public class Clod {
|
||||||
|
|
||||||
|
public static final String MODID = "clod";
|
||||||
|
private static final Logger LOGGER = LogUtils.getLogger();
|
||||||
|
|
||||||
|
private ClodHttpServer httpServer;
|
||||||
|
|
||||||
|
public Clod(IEventBus modEventBus, ModContainer modContainer) {
|
||||||
|
ModEntities.ENTITY_TYPES.register(modEventBus);
|
||||||
|
|
||||||
|
modEventBus.addListener(this::commonSetup);
|
||||||
|
modEventBus.addListener(this::onAttributeCreation);
|
||||||
|
|
||||||
|
NeoForge.EVENT_BUS.register(this);
|
||||||
|
|
||||||
|
LOGGER.info("Clod mod initialized!");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void commonSetup(final FMLCommonSetupEvent event) {
|
||||||
|
LOGGER.info("Clod common setup");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onAttributeCreation(final EntityAttributeCreationEvent event) {
|
||||||
|
event.put(ModEntities.CLOD_ENTITY.get(), ClodEntity.createAttributes().build());
|
||||||
|
}
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public void onRegisterCommands(RegisterCommandsEvent event) {
|
||||||
|
ClodCommands.register(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public void onServerStarted(ServerStartedEvent event) {
|
||||||
|
httpServer = new ClodHttpServer(event.getServer());
|
||||||
|
httpServer.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public void onServerStopping(ServerStoppingEvent event) {
|
||||||
|
if (httpServer != null) {
|
||||||
|
httpServer.stop();
|
||||||
|
httpServer = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public void onServerChat(ServerChatEvent event) {
|
||||||
|
String message = event.getRawText();
|
||||||
|
if (message.startsWith("!clod ")) {
|
||||||
|
String stripped = message.substring(6);
|
||||||
|
String player = event.getPlayer().getName().getString();
|
||||||
|
if (httpServer != null) {
|
||||||
|
httpServer.onChatMessage(player, stripped);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventBusSubscriber(modid = MODID, value = Dist.CLIENT)
|
||||||
|
public static class ClientEvents {
|
||||||
|
@SubscribeEvent
|
||||||
|
public static void onRegisterRenderers(EntityRenderersEvent.RegisterRenderers event) {
|
||||||
|
event.registerEntityRenderer(ModEntities.CLOD_ENTITY.get(), ClodEntityRenderer::new);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public static void onRegisterLayerDefinitions(EntityRenderersEvent.RegisterLayerDefinitions event) {
|
||||||
|
event.registerLayerDefinition(ClodEntityRenderer.CLOD_LAYER, ClodModel::createBodyLayer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
package com.clod.clod.client;
|
||||||
|
|
||||||
|
import com.clod.clod.entity.ClodEntity;
|
||||||
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
|
import net.minecraft.client.model.geom.ModelLayerLocation;
|
||||||
|
import net.minecraft.client.renderer.MultiBufferSource;
|
||||||
|
import net.minecraft.client.renderer.entity.EntityRendererProvider;
|
||||||
|
import net.minecraft.client.renderer.entity.MobRenderer;
|
||||||
|
import net.minecraft.core.particles.DustParticleOptions;
|
||||||
|
import net.minecraft.core.particles.ParticleTypes;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.util.Mth;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import net.neoforged.api.distmarker.Dist;
|
||||||
|
import net.neoforged.api.distmarker.OnlyIn;
|
||||||
|
import org.joml.Vector3f;
|
||||||
|
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
public class ClodEntityRenderer extends MobRenderer<ClodEntity, ClodModel> {
|
||||||
|
|
||||||
|
public static final ModelLayerLocation CLOD_LAYER =
|
||||||
|
new ModelLayerLocation(ResourceLocation.fromNamespaceAndPath("clod", "clod"), "main");
|
||||||
|
|
||||||
|
private static final ResourceLocation TEXTURE =
|
||||||
|
ResourceLocation.fromNamespaceAndPath("clod", "textures/entity/clod.png");
|
||||||
|
|
||||||
|
public ClodEntityRenderer(EntityRendererProvider.Context context) {
|
||||||
|
super(context, new ClodModel(context.bakeLayer(CLOD_LAYER)), 0.4F);
|
||||||
|
this.addLayer(new ClodEyeGlowLayer(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResourceLocation getTextureLocation(ClodEntity entity) {
|
||||||
|
return TEXTURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(ClodEntity entity, float entityYaw, float partialTick,
|
||||||
|
PoseStack poseStack, MultiBufferSource bufferSource, int packedLight) {
|
||||||
|
super.render(entity, entityYaw, partialTick, poseStack, bufferSource, packedLight);
|
||||||
|
|
||||||
|
if (!entity.level().isClientSide()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String state = entity.getClodState();
|
||||||
|
double x = entity.getX();
|
||||||
|
double y = entity.getY();
|
||||||
|
double z = entity.getZ();
|
||||||
|
|
||||||
|
switch (state) {
|
||||||
|
case "idle":
|
||||||
|
// 10% chance per frame — warm dust drifting upward
|
||||||
|
if (entity.getRandom().nextFloat() < 0.1F) {
|
||||||
|
entity.level().addParticle(
|
||||||
|
new DustParticleOptions(new Vector3f(212F / 255F, 132F / 255F, 91F / 255F), 0.6F),
|
||||||
|
x + (entity.getRandom().nextDouble() - 0.5) * 0.6,
|
||||||
|
y + 0.5 + entity.getRandom().nextDouble() * 0.5,
|
||||||
|
z + (entity.getRandom().nextDouble() - 0.5) * 0.6,
|
||||||
|
0.0, 0.02, 0.0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "thinking":
|
||||||
|
// 3 particles in a spinning ring above head
|
||||||
|
float tickProgress = entity.tickCount + partialTick;
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
float angle = tickProgress * 0.15F + (i * (float) (Math.PI * 2.0 / 3.0));
|
||||||
|
double ringX = x + Mth.cos(angle) * 0.5;
|
||||||
|
double ringY = y + 2.0;
|
||||||
|
double ringZ = z + Mth.sin(angle) * 0.5;
|
||||||
|
entity.level().addParticle(
|
||||||
|
new DustParticleOptions(new Vector3f(212F / 255F, 132F / 255F, 91F / 255F), 0.8F),
|
||||||
|
ringX, ringY, ringZ,
|
||||||
|
0.0, 0.01, 0.0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "building":
|
||||||
|
// 30% chance — electric spark near right hand
|
||||||
|
if (entity.getRandom().nextFloat() < 0.3F) {
|
||||||
|
float yawRad = entity.yBodyRot * ((float) Math.PI / 180F);
|
||||||
|
double handX = x - Mth.sin(yawRad) * 0.5 - Mth.cos(yawRad) * 0.4;
|
||||||
|
double handY = y + 1.0;
|
||||||
|
double handZ = z + Mth.cos(yawRad) * 0.5 - Mth.sin(yawRad) * 0.4;
|
||||||
|
entity.level().addParticle(ParticleTypes.ELECTRIC_SPARK,
|
||||||
|
handX, handY, handZ,
|
||||||
|
(entity.getRandom().nextDouble() - 0.5) * 0.1,
|
||||||
|
entity.getRandom().nextDouble() * 0.05,
|
||||||
|
(entity.getRandom().nextDouble() - 0.5) * 0.1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "moving":
|
||||||
|
// 40% chance — warm dust trail behind entity
|
||||||
|
if (entity.getRandom().nextFloat() < 0.4F) {
|
||||||
|
Vec3 movement = entity.getDeltaMovement();
|
||||||
|
entity.level().addParticle(
|
||||||
|
new DustParticleOptions(new Vector3f(212F / 255F, 132F / 255F, 91F / 255F), 0.5F),
|
||||||
|
x + (entity.getRandom().nextDouble() - 0.5) * 0.3,
|
||||||
|
y + 0.1,
|
||||||
|
z + (entity.getRandom().nextDouble() - 0.5) * 0.3,
|
||||||
|
-movement.x * 0.5, 0.02, -movement.z * 0.5);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package com.clod.clod.client;
|
||||||
|
|
||||||
|
import com.clod.clod.entity.ClodEntity;
|
||||||
|
import net.minecraft.client.renderer.RenderType;
|
||||||
|
import net.minecraft.client.renderer.entity.RenderLayerParent;
|
||||||
|
import net.minecraft.client.renderer.entity.layers.EyesLayer;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.neoforged.api.distmarker.Dist;
|
||||||
|
import net.neoforged.api.distmarker.OnlyIn;
|
||||||
|
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
public class ClodEyeGlowLayer extends EyesLayer<ClodEntity, ClodModel> {
|
||||||
|
|
||||||
|
private static final RenderType CLOD_EYES = RenderType.eyes(
|
||||||
|
ResourceLocation.fromNamespaceAndPath("clod", "textures/entity/clod_eyes.png"));
|
||||||
|
|
||||||
|
public ClodEyeGlowLayer(RenderLayerParent<ClodEntity, ClodModel> renderer) {
|
||||||
|
super(renderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RenderType renderType() {
|
||||||
|
return CLOD_EYES;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,131 @@
|
|||||||
|
package com.clod.clod.client;
|
||||||
|
|
||||||
|
import com.clod.clod.entity.ClodEntity;
|
||||||
|
import net.minecraft.client.model.HumanoidModel;
|
||||||
|
import net.minecraft.client.model.geom.ModelPart;
|
||||||
|
import net.minecraft.client.model.geom.PartPose;
|
||||||
|
import net.minecraft.client.model.geom.builders.CubeDeformation;
|
||||||
|
import net.minecraft.client.model.geom.builders.CubeListBuilder;
|
||||||
|
import net.minecraft.client.model.geom.builders.LayerDefinition;
|
||||||
|
import net.minecraft.client.model.geom.builders.MeshDefinition;
|
||||||
|
import net.minecraft.client.model.geom.builders.PartDefinition;
|
||||||
|
import net.minecraft.util.Mth;
|
||||||
|
import net.neoforged.api.distmarker.Dist;
|
||||||
|
import net.neoforged.api.distmarker.OnlyIn;
|
||||||
|
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
public class ClodModel extends HumanoidModel<ClodEntity> {
|
||||||
|
|
||||||
|
private final ModelPart antenna;
|
||||||
|
|
||||||
|
public ClodModel(ModelPart root) {
|
||||||
|
super(root);
|
||||||
|
this.antenna = this.head.getChild("antenna");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LayerDefinition createBodyLayer() {
|
||||||
|
MeshDefinition meshdefinition = new MeshDefinition();
|
||||||
|
PartDefinition partdefinition = meshdefinition.getRoot();
|
||||||
|
|
||||||
|
// Head: 10x10x10, pivot at Y=8
|
||||||
|
PartDefinition head = partdefinition.addOrReplaceChild("head",
|
||||||
|
CubeListBuilder.create().texOffs(0, 0)
|
||||||
|
.addBox(-5.0F, -10.0F, -5.0F, 10.0F, 10.0F, 10.0F, CubeDeformation.NONE),
|
||||||
|
PartPose.offset(0.0F, 8.0F, 0.0F));
|
||||||
|
|
||||||
|
// Antenna: child of head, 1x3x1
|
||||||
|
head.addOrReplaceChild("antenna",
|
||||||
|
CubeListBuilder.create().texOffs(0, 46)
|
||||||
|
.addBox(-0.5F, -13.0F, -0.5F, 1.0F, 3.0F, 1.0F, CubeDeformation.NONE),
|
||||||
|
PartPose.ZERO);
|
||||||
|
|
||||||
|
// Hat: empty (required by HumanoidModel parent)
|
||||||
|
partdefinition.addOrReplaceChild("hat",
|
||||||
|
CubeListBuilder.create().texOffs(32, 0)
|
||||||
|
.addBox(0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, CubeDeformation.NONE),
|
||||||
|
PartPose.offset(0.0F, 8.0F, 0.0F));
|
||||||
|
|
||||||
|
// Body: 10x8x6, pivot at Y=8
|
||||||
|
partdefinition.addOrReplaceChild("body",
|
||||||
|
CubeListBuilder.create().texOffs(0, 20)
|
||||||
|
.addBox(-5.0F, 0.0F, -3.0F, 10.0F, 8.0F, 6.0F, CubeDeformation.NONE),
|
||||||
|
PartPose.offset(0.0F, 8.0F, 0.0F));
|
||||||
|
|
||||||
|
// Right arm: 4x8x4, pivot at Y=9, X=-7
|
||||||
|
partdefinition.addOrReplaceChild("right_arm",
|
||||||
|
CubeListBuilder.create().texOffs(40, 20)
|
||||||
|
.addBox(-3.0F, -1.0F, -2.0F, 4.0F, 8.0F, 4.0F, CubeDeformation.NONE),
|
||||||
|
PartPose.offset(-7.0F, 9.0F, 0.0F));
|
||||||
|
|
||||||
|
// Left arm: 4x8x4, pivot at Y=9, X=+7
|
||||||
|
partdefinition.addOrReplaceChild("left_arm",
|
||||||
|
CubeListBuilder.create().texOffs(40, 32)
|
||||||
|
.addBox(-1.0F, -1.0F, -2.0F, 4.0F, 8.0F, 4.0F, CubeDeformation.NONE),
|
||||||
|
PartPose.offset(7.0F, 9.0F, 0.0F));
|
||||||
|
|
||||||
|
// Right leg: 4x8x4, pivot at Y=16, X=-2.5
|
||||||
|
partdefinition.addOrReplaceChild("right_leg",
|
||||||
|
CubeListBuilder.create().texOffs(0, 34)
|
||||||
|
.addBox(-2.0F, 0.0F, -2.0F, 4.0F, 8.0F, 4.0F, CubeDeformation.NONE),
|
||||||
|
PartPose.offset(-2.5F, 16.0F, 0.0F));
|
||||||
|
|
||||||
|
// Left leg: 4x8x4, pivot at Y=16, X=+2.5
|
||||||
|
partdefinition.addOrReplaceChild("left_leg",
|
||||||
|
CubeListBuilder.create().texOffs(16, 34)
|
||||||
|
.addBox(-2.0F, 0.0F, -2.0F, 4.0F, 8.0F, 4.0F, CubeDeformation.NONE),
|
||||||
|
PartPose.offset(2.5F, 16.0F, 0.0F));
|
||||||
|
|
||||||
|
return LayerDefinition.create(meshdefinition, 64, 64);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setupAnim(ClodEntity entity, float limbSwing, float limbSwingAmount,
|
||||||
|
float ageInTicks, float netHeadYaw, float headPitch) {
|
||||||
|
super.setupAnim(entity, limbSwing, limbSwingAmount, ageInTicks, netHeadYaw, headPitch);
|
||||||
|
|
||||||
|
// Hide the hat part — we don't use it
|
||||||
|
this.hat.visible = false;
|
||||||
|
|
||||||
|
String state = entity.getClodState();
|
||||||
|
|
||||||
|
// Default antenna bob
|
||||||
|
this.antenna.xRot = Mth.sin(ageInTicks * 0.15F) * 0.15F;
|
||||||
|
|
||||||
|
switch (state) {
|
||||||
|
case "thinking":
|
||||||
|
// Arms forward and together
|
||||||
|
this.rightArm.xRot = -0.8F;
|
||||||
|
this.leftArm.xRot = -0.8F;
|
||||||
|
this.rightArm.zRot = 0.3F; // inward
|
||||||
|
this.leftArm.zRot = -0.3F; // inward
|
||||||
|
// Body sway
|
||||||
|
this.body.zRot = Mth.sin(ageInTicks * 0.08F) * 0.05F;
|
||||||
|
// Faster antenna bob
|
||||||
|
this.antenna.xRot = Mth.sin(ageInTicks * 0.4F) * 0.25F;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "building":
|
||||||
|
// Right arm extended forward
|
||||||
|
this.rightArm.xRot = -1.0F;
|
||||||
|
this.rightArm.zRot = 0.0F;
|
||||||
|
// Left arm relaxed
|
||||||
|
this.leftArm.xRot = 0.1F;
|
||||||
|
this.leftArm.zRot = -0.1F;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "moving":
|
||||||
|
// Parent walk cycle handles this — no override needed
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "idle":
|
||||||
|
default:
|
||||||
|
// Gentle breathing/sway on arms
|
||||||
|
float breathe = Mth.sin(ageInTicks * 0.067F) * 0.05F;
|
||||||
|
this.rightArm.xRot += breathe;
|
||||||
|
this.leftArm.xRot += breathe;
|
||||||
|
this.rightArm.zRot = 0.08F + Mth.sin(ageInTicks * 0.067F) * 0.02F;
|
||||||
|
this.leftArm.zRot = -0.08F - Mth.sin(ageInTicks * 0.067F) * 0.02F;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package com.clod.clod.command;
|
||||||
|
|
||||||
|
import com.clod.clod.entity.ClodEntity;
|
||||||
|
import com.clod.clod.init.ModEntities;
|
||||||
|
import com.mojang.brigadier.Command;
|
||||||
|
import net.minecraft.commands.Commands;
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.neoforged.neoforge.event.RegisterCommandsEvent;
|
||||||
|
|
||||||
|
public class ClodCommands {
|
||||||
|
|
||||||
|
public static void register(RegisterCommandsEvent event) {
|
||||||
|
event.getDispatcher().register(
|
||||||
|
Commands.literal("clod")
|
||||||
|
.then(Commands.literal("spawn")
|
||||||
|
.requires(cs -> cs.hasPermission(2))
|
||||||
|
.executes(ctx -> {
|
||||||
|
ServerPlayer player = ctx.getSource().getPlayerOrException();
|
||||||
|
ServerLevel level = player.serverLevel();
|
||||||
|
|
||||||
|
ClodEntity entity = new ClodEntity(ModEntities.CLOD_ENTITY.get(), level);
|
||||||
|
entity.moveTo(player.getX(), player.getY(), player.getZ(),
|
||||||
|
player.getYRot(), player.getXRot());
|
||||||
|
level.addFreshEntity(entity);
|
||||||
|
ClodEntity.instance = entity;
|
||||||
|
|
||||||
|
ctx.getSource().sendSuccess(
|
||||||
|
() -> Component.literal("Clod entity spawned!"), true);
|
||||||
|
return Command.SINGLE_SUCCESS;
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
package com.clod.clod.entity;
|
||||||
|
|
||||||
|
import net.minecraft.network.syncher.EntityDataAccessor;
|
||||||
|
import net.minecraft.network.syncher.EntityDataSerializers;
|
||||||
|
import net.minecraft.network.syncher.SynchedEntityData;
|
||||||
|
import net.minecraft.world.SimpleContainer;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.entity.EntityType;
|
||||||
|
import net.minecraft.world.entity.PathfinderMob;
|
||||||
|
import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
|
||||||
|
import net.minecraft.world.entity.ai.attributes.Attributes;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class ClodEntity extends PathfinderMob {
|
||||||
|
|
||||||
|
public static ClodEntity instance;
|
||||||
|
|
||||||
|
private static final Set<String> VALID_STATES = Set.of("idle", "thinking", "building", "moving");
|
||||||
|
|
||||||
|
private static final EntityDataAccessor<String> STATE =
|
||||||
|
SynchedEntityData.defineId(ClodEntity.class, EntityDataSerializers.STRING);
|
||||||
|
|
||||||
|
private final SimpleContainer inventory = new SimpleContainer(36);
|
||||||
|
|
||||||
|
public ClodEntity(EntityType<? extends PathfinderMob> type, Level level) {
|
||||||
|
super(type, level);
|
||||||
|
this.getNavigation().setCanFloat(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SimpleContainer getInventory() {
|
||||||
|
return this.inventory;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void remove(Entity.RemovalReason reason) {
|
||||||
|
super.remove(reason);
|
||||||
|
if (instance == this) {
|
||||||
|
instance = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void defineSynchedData(SynchedEntityData.Builder builder) {
|
||||||
|
super.defineSynchedData(builder);
|
||||||
|
builder.define(STATE, "idle");
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getClodState() {
|
||||||
|
return this.entityData.get(STATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setClodState(String state) {
|
||||||
|
if (VALID_STATES.contains(state)) {
|
||||||
|
this.entityData.set(STATE, state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isInvulnerable() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean removeWhenFarAway(double distanceToClosestPlayer) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void registerGoals() {
|
||||||
|
// No AI goals
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AttributeSupplier.Builder createAttributes() {
|
||||||
|
return PathfinderMob.createMobAttributes()
|
||||||
|
.add(Attributes.MAX_HEALTH, 20.0)
|
||||||
|
.add(Attributes.MOVEMENT_SPEED, 0.3);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package com.clod.clod.init;
|
||||||
|
|
||||||
|
import com.clod.clod.Clod;
|
||||||
|
import com.clod.clod.entity.ClodEntity;
|
||||||
|
import net.minecraft.core.registries.Registries;
|
||||||
|
import net.minecraft.world.entity.EntityType;
|
||||||
|
import net.minecraft.world.entity.MobCategory;
|
||||||
|
import net.neoforged.neoforge.registries.DeferredHolder;
|
||||||
|
import net.neoforged.neoforge.registries.DeferredRegister;
|
||||||
|
|
||||||
|
public class ModEntities {
|
||||||
|
|
||||||
|
public static final DeferredRegister<EntityType<?>> ENTITY_TYPES =
|
||||||
|
DeferredRegister.create(Registries.ENTITY_TYPE, Clod.MODID);
|
||||||
|
|
||||||
|
public static final DeferredHolder<EntityType<?>, EntityType<ClodEntity>> CLOD_ENTITY =
|
||||||
|
ENTITY_TYPES.register("clod_entity", () -> EntityType.Builder.of(ClodEntity::new, MobCategory.MISC)
|
||||||
|
.sized(0.8f, 1.5f)
|
||||||
|
.build(Clod.MODID + ":clod_entity"));
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
After Width: | Height: | Size: 439 B |
Binary file not shown.
|
After Width: | Height: | Size: 117 B |
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"pack": {
|
||||||
|
"description": "Clod resources",
|
||||||
|
"pack_format": 34
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
modLoader="javafml"
|
||||||
|
loaderVersion="${loader_version_range}"
|
||||||
|
license="${mod_license}"
|
||||||
|
|
||||||
|
[[mods]]
|
||||||
|
modId="${mod_id}"
|
||||||
|
version="${mod_version}"
|
||||||
|
displayName="${mod_name}"
|
||||||
|
authors="${mod_authors}"
|
||||||
|
description='''${mod_description}'''
|
||||||
|
|
||||||
|
[[dependencies.${mod_id}]]
|
||||||
|
modId="neoforge"
|
||||||
|
type="required"
|
||||||
|
versionRange="${neo_version_range}"
|
||||||
|
ordering="NONE"
|
||||||
|
side="BOTH"
|
||||||
|
|
||||||
|
[[dependencies.${mod_id}]]
|
||||||
|
modId="minecraft"
|
||||||
|
type="required"
|
||||||
|
versionRange="${minecraft_version_range}"
|
||||||
|
ordering="NONE"
|
||||||
|
side="BOTH"
|
||||||
Reference in New Issue
Block a user