Skip to content

Commit

Permalink
Merge branch 'master' into feat/schemas
Browse files Browse the repository at this point in the history
  • Loading branch information
DataM0del authored Dec 28, 2024
2 parents 17c8ecf + ad2fd3c commit 980f555
Show file tree
Hide file tree
Showing 96 changed files with 1,647 additions and 822 deletions.
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

</div>

[Pumpkin](https://snowiiii.github.io/Pumpkin/) is a Minecraft server built entirely in Rust, offering a fast, efficient,
[Pumpkin](https://snowiiii.github.io/Pumpkin-Website/) is a Minecraft server built entirely in Rust, offering a fast, efficient,
and customizable experience. It prioritizes performance and player enjoyment while adhering to the core mechanics of the game.

![image](https://github.com/user-attachments/assets/7e2e865e-b150-4675-a2d5-b52f9900378e)
Expand Down Expand Up @@ -79,6 +79,7 @@ and customizable experience. It prioritizes performance and player enjoyment whi
- [x] Particles
- [x] Chat
- [x] Commands
- [x] OP Permission
- Proxy
- [x] Bungeecord
- [x] Velocity
Expand All @@ -87,15 +88,15 @@ Check out our [Github Project](https://github.com/users/Snowiiii/projects/12/vie

## How to run

See our [Quick Start](https://snowiiii.github.io/Pumpkin/about/quick-start.html) Guide to get Pumpkin running
See our [Quick Start](https://snowiiii.github.io/Pumpkin-Website/about/quick-start.html) Guide to get Pumpkin running

## Contributions

Contributions are welcome! See [CONTRIBUTING.md](CONTRIBUTING.md)

## Docs

The Documentation of Pumpkin can be found at https://snowiiii.github.io/Pumpkin/
The Documentation of Pumpkin can be found at https://snowiiii.github.io/Pumpkin-Website/

## Communication

Expand Down
1 change: 1 addition & 0 deletions assets/entities.json

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ services:
pumpkin:
build: .
ports:
- 25565:25565
- "25565:25565"
volumes:
- ./data:/pumpkin
stdin_open: true
tty: true
2 changes: 1 addition & 1 deletion extractor/gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ kotlin_loader_version=1.13.0+kotlin.2.1.0
mod_version=1.0-SNAPSHOT
maven_group=de.snowii
archives_base_name=extractor
fabric_version=0.112.1+1.21.4
fabric_version=0.113.0+1.21.4
2 changes: 1 addition & 1 deletion extractor/gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
Expand Down
5 changes: 2 additions & 3 deletions extractor/gradlew
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,7 @@ done
# 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 -P "${APP_HOME:-./}" > /dev/null && printf '%s
' "$PWD" ) || exit
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit

# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
Expand Down Expand Up @@ -203,7 +202,7 @@ 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"'
DEFAULT_JVM_OPTS='-Dfile.encoding=UTF-8 "-Xmx64m" "-Xms64m"'

# Collect all arguments for the java command:
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
Expand Down
2 changes: 1 addition & 1 deletion extractor/gradlew.bat
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ set APP_HOME=%DIRNAME%
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"
set DEFAULT_JVM_OPTS=-Dfile.encoding=UTF-8 "-Xmx64m" "-Xms64m"

@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
Expand Down
2 changes: 1 addition & 1 deletion extractor/src/main/kotlin/de/snowii/extractor/Extractor.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package de.snowii.extractor

import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.google.gson.JsonElement
import de.snowii.extractor.extractors.*
Expand Down Expand Up @@ -31,6 +30,7 @@ class Extractor : ModInitializer {
Packets(),
Screens(),
Tags(),
Entities(),
Items(),
Blocks(),
Tests(),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package de.snowii.extractor.extractors

import com.google.gson.JsonArray
import com.google.gson.JsonElement
import com.google.gson.JsonObject
import de.snowii.extractor.Extractor
import net.minecraft.entity.LivingEntity
import net.minecraft.entity.SpawnReason
import net.minecraft.registry.Registries
import net.minecraft.server.MinecraftServer

class Entities : Extractor.Extractor {
override fun fileName(): String {
return "entities.json"
}

override fun extract(server: MinecraftServer): JsonElement {
val entitiesJson = JsonObject()
for (entityType in Registries.ENTITY_TYPE) {
val entity = entityType.create(server.overworld!!, SpawnReason.NATURAL) ?: continue
val entityJson = JsonObject()
entityJson.addProperty("id", Registries.ENTITY_TYPE.getRawId(entityType))
if (entity is LivingEntity) {
entityJson.addProperty("max_health", entity.maxHealth)

}
entityJson.addProperty("attackable", entity.isAttackable)
entityJson.addProperty("summonable", entityType.isSummonable)
entityJson.addProperty("fire_immune", entityType.isFireImmune)
val dimension = JsonArray()
dimension.add(entityType.dimensions.width)
dimension.add(entityType.dimensions.height)
entityJson.add("dimension", dimension)

entitiesJson.add(
Registries.ENTITY_TYPE.getId(entityType).path, entityJson
)
}

return entitiesJson
}
}
217 changes: 106 additions & 111 deletions extractor/src/main/kotlin/de/snowii/extractor/extractors/Tests.kt
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@

package de.snowii.extractor.extractors

import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.google.gson.JsonArray
import com.google.gson.JsonElement
import de.snowii.extractor.Extractor
Expand All @@ -11,129 +8,127 @@ import net.minecraft.block.BlockState
import net.minecraft.block.Blocks
import net.minecraft.registry.BuiltinRegistries
import net.minecraft.registry.RegistryKeys
import net.minecraft.registry.RegistryWrapper
import net.minecraft.registry.RegistryWrapper.WrapperLookup
import net.minecraft.registry.entry.RegistryEntry.Reference
import net.minecraft.server.MinecraftServer
import net.minecraft.util.math.noise.DoublePerlinNoiseSampler.NoiseParameters
import net.minecraft.util.math.ChunkPos
import net.minecraft.world.gen.chunk.AquiferSampler
import net.minecraft.world.gen.chunk.Blender
import net.minecraft.world.gen.chunk.ChunkGeneratorSettings
import net.minecraft.world.gen.chunk.ChunkNoiseSampler
import net.minecraft.world.gen.chunk.GenerationShapeConfig
import net.minecraft.world.gen.densityfunction.DensityFunction.NoisePos;
import net.minecraft.world.gen.densityfunction.DensityFunction.EachApplier;
import net.minecraft.world.gen.chunk.*
import net.minecraft.world.gen.densityfunction.DensityFunction.EachApplier
import net.minecraft.world.gen.densityfunction.DensityFunction.NoisePos
import net.minecraft.world.gen.densityfunction.DensityFunctionTypes
import net.minecraft.world.gen.noise.NoiseConfig

import java.lang.reflect.Method
import java.util.Arrays
import kotlin.reflect.full.createType
import kotlin.reflect.full.declaredFunctions
import kotlin.reflect.jvm.javaMethod
import kotlin.reflect.KFunction
import kotlin.reflect.full.declaredFunctions

class Tests : Extractor.Extractor {
override fun fileName(): String = "chunk.json"

private fun createFluidLevelSampler(settings: ChunkGeneratorSettings): AquiferSampler.FluidLevelSampler {
val fluidLevel = AquiferSampler.FluidLevel(-54, Blocks.LAVA.getDefaultState());
val i = settings.seaLevel();
val fluidLevel2 = AquiferSampler.FluidLevel(i, settings.defaultFluid());
return AquiferSampler.FluidLevelSampler {_, y, _ -> if (y < Math.min(-54, i)) fluidLevel else fluidLevel2};
}

private fun get_index(config: GenerationShapeConfig, x: Int, y: Int, z: Int): Int {
if (x < 0 || y < 0 || z < 0) {
System.err.println("Bad local pos");
System.exit(1);
}
return config.height() * 16 * x + 16 * y + z
}

// This is basically just what NoiseChunkGenerator is doing
private fun populate_noise(start_x: Int, start_z: Int, sampler: ChunkNoiseSampler, config: GenerationShapeConfig, settings: ChunkGeneratorSettings): IntArray? {
val result = IntArray(16 * 16 * config.height())

for (method: KFunction<*> in sampler::class.declaredFunctions) {
if (method.name.equals("sampleBlockState")) {
sampler.sampleStartDensity()
val k = config.horizontalCellBlockCount()
val l = config.verticalCellBlockCount()

val m = 16 / k
val n = 16 / k
private fun createFluidLevelSampler(settings: ChunkGeneratorSettings): AquiferSampler.FluidLevelSampler {
val fluidLevel = AquiferSampler.FluidLevel(-54, Blocks.LAVA.defaultState)
val i = settings.seaLevel()
val fluidLevel2 = AquiferSampler.FluidLevel(i, settings.defaultFluid())
return AquiferSampler.FluidLevelSampler { _, y, _ -> if (y < Math.min(-54, i)) fluidLevel else fluidLevel2 }
}

val cellHeight = config.height() / l
val minimumCellY = config.minimumY() / l
private fun get_index(config: GenerationShapeConfig, x: Int, y: Int, z: Int): Int {
if (x < 0 || y < 0 || z < 0) {
System.err.println("Bad local pos")
System.exit(1)
}
return config.height() * 16 * x + 16 * y + z
}

for (o in 0..<m) {
sampler.sampleEndDensity(o)
for (p in 0..<n) {
for (r in (0..<cellHeight).reversed()) {
sampler.onSampledCellCorners(r, p)
for (s in (0..<l).reversed()) {
val t = (minimumCellY + r) * l + s
val d = s.toDouble() / l.toDouble()
sampler.interpolateY(t, d)
for (w in 0..<k) {
val x = start_x + o * k + w
val y = x and 15
val e = w.toDouble() / k.toDouble()
sampler.interpolateX(x, e)
for (z in 0..<k) {
val aa = start_z + p * k + z
val ab = aa and 15
val f = z.toDouble() / k.toDouble()
sampler.interpolateZ(aa, f)
var blockstate = method.call(sampler) as BlockState?
if (blockstate == null) {
blockstate = settings.defaultBlock()
}
val index = this.get_index(config, y, t - config.minimumY(), ab)
result[index] = Block.getRawIdFromState(blockstate)
}
}
}
}
}
sampler.swapBuffers()
}
sampler.stopInterpolation()
return result
}
}
System.err.println("No valid method found for block state sampler!");
return null;
}
// This is basically just what NoiseChunkGenerator is doing
private fun populate_noise(
start_x: Int,
start_z: Int,
sampler: ChunkNoiseSampler,
config: GenerationShapeConfig,
settings: ChunkGeneratorSettings
): IntArray? {
val result = IntArray(16 * 16 * config.height())

for (method: KFunction<*> in sampler::class.declaredFunctions) {
if (method.name.equals("sampleBlockState")) {
sampler.sampleStartDensity()
val k = config.horizontalCellBlockCount()
val l = config.verticalCellBlockCount()

val m = 16 / k
val n = 16 / k

val cellHeight = config.height() / l
val minimumCellY = config.minimumY() / l

for (o in 0..<m) {
sampler.sampleEndDensity(o)
for (p in 0..<n) {
for (r in (0..<cellHeight).reversed()) {
sampler.onSampledCellCorners(r, p)
for (s in (0..<l).reversed()) {
val t = (minimumCellY + r) * l + s
val d = s.toDouble() / l.toDouble()
sampler.interpolateY(t, d)
for (w in 0..<k) {
val x = start_x + o * k + w
val y = x and 15
val e = w.toDouble() / k.toDouble()
sampler.interpolateX(x, e)
for (z in 0..<k) {
val aa = start_z + p * k + z
val ab = aa and 15
val f = z.toDouble() / k.toDouble()
sampler.interpolateZ(aa, f)
var blockstate = method.call(sampler) as BlockState?
if (blockstate == null) {
blockstate = settings.defaultBlock()
}
val index = this.get_index(config, y, t - config.minimumY(), ab)
result[index] = Block.getRawIdFromState(blockstate)
}
}
}
}
}
sampler.swapBuffers()
}
sampler.stopInterpolation()
return result
}
}
System.err.println("No valid method found for block state sampler!")
return null
}

// Dumps a chunk to an array of block state ids
override fun extract(server: MinecraftServer): JsonElement {
val topLevelJson = JsonArray()
val seed = 0L
val chunk_pos = ChunkPos(7, 4)

val lookup = BuiltinRegistries.createWrapperLookup()
val wrapper = lookup.getOrThrow(RegistryKeys.CHUNK_GENERATOR_SETTINGS)
val noise_params = lookup.getOrThrow(RegistryKeys.NOISE_PARAMETERS)

val ref = wrapper.getOrThrow(ChunkGeneratorSettings.OVERWORLD)
val settings = ref.value()
val config = NoiseConfig.create(settings, noise_params, seed)

// Overworld shape config
val shape = GenerationShapeConfig(-64, 384, 1, 2)
val test_sampler = ChunkNoiseSampler(16 / shape.horizontalCellBlockCount(), config, chunk_pos.startX, chunk_pos.startZ,
shape, object: DensityFunctionTypes.Beardifying{
override fun maxValue(): Double = 0.0
override fun minValue(): Double = 0.0
override fun sample(pos: NoisePos): Double = 0.0
override fun fill(densities: DoubleArray, applier: EachApplier) {densities.fill(0.0)}
}, settings, createFluidLevelSampler(settings), Blender.getNoBlending())

val data = populate_noise(chunk_pos.startX, chunk_pos.startZ, test_sampler, shape, settings)
data?.forEach { state ->
val seed = 0L
val chunk_pos = ChunkPos(7, 4)

val lookup = BuiltinRegistries.createWrapperLookup()
val wrapper = lookup.getOrThrow(RegistryKeys.CHUNK_GENERATOR_SETTINGS)
val noise_params = lookup.getOrThrow(RegistryKeys.NOISE_PARAMETERS)

val ref = wrapper.getOrThrow(ChunkGeneratorSettings.OVERWORLD)
val settings = ref.value()
val config = NoiseConfig.create(settings, noise_params, seed)

// Overworld shape config
val shape = GenerationShapeConfig(-64, 384, 1, 2)
val test_sampler =
ChunkNoiseSampler(
16 / shape.horizontalCellBlockCount(), config, chunk_pos.startX, chunk_pos.startZ,
shape, object : DensityFunctionTypes.Beardifying {
override fun maxValue(): Double = 0.0
override fun minValue(): Double = 0.0
override fun sample(pos: NoisePos): Double = 0.0
override fun fill(densities: DoubleArray, applier: EachApplier) {
densities.fill(0.0)
}
}, settings, createFluidLevelSampler(settings), Blender.getNoBlending()
)

val data = populate_noise(chunk_pos.startX, chunk_pos.startZ, test_sampler, shape, settings)
data?.forEach { state ->
topLevelJson.add(state)
}

Expand Down
1 change: 1 addition & 0 deletions pumpkin-config/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ schemars = ["dep:schemars", "pumpkin-core/schemars"]
pumpkin-core = { path = "../pumpkin-core" }
serde.workspace = true
log.workspace = true
uuid.workspace = true

toml = "0.8"
# used by the generate schemas script
Expand Down
Loading

0 comments on commit 980f555

Please sign in to comment.