Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
3f67d34
Add a testing suite (#14)
ShaneBeee Feb 12, 2026
ea1ef48
Block - add methods for block health and damage handling
ShaneBeee Feb 12, 2026
a1e00d7
ExprBlockHealth - add block health expression
ShaneBeee Feb 12, 2026
c308de8
EffDamageBlock - add block damage effect
ShaneBeee Feb 12, 2026
6221c68
ExprWorldTime - add world date/time expression
ShaneBeee Feb 12, 2026
48e690d
ExprWorldTime - rename and add setter
ShaneBeee Feb 12, 2026
138b38c
DefaultFunctions - add some date/time functions
ShaneBeee Feb 12, 2026
cd7d4a4
SkriptConfig - add default date/time formats
ShaneBeee Feb 12, 2026
032f900
EffServerShutdown - add shutdown effect
ShaneBeee Feb 12, 2026
d23eab0
ExprItemContainer - add more combined types
ShaneBeee Feb 13, 2026
c15ef49
EffOpenItemContainer - add effect to open an item container
ShaneBeee Feb 13, 2026
97bf293
EffFreeze - add effect to freeze
ShaneBeee Feb 13, 2026
a70027e
CondEntityIsFrozen - add condition to check if frozen
ShaneBeee Feb 13, 2026
678bd18
ExprWorldDateTime - add support for adding/removing duration
ShaneBeee Feb 13, 2026
4188858
SkriptConfig - add a date/time pattern validator
ShaneBeee Feb 13, 2026
bfc4e53
ExprEnvironmentAtLocation - add expression for environment at location
ShaneBeee Feb 13, 2026
34f0dec
Merge branch 'master' into dev/feature
ShaneBeee Feb 14, 2026
147e7ea
AssetStoreUtils - add environment methods
ShaneBeee Feb 14, 2026
0a8fce2
Add view radius expressions
ShaneBeee Feb 15, 2026
1f542b6
TestRunnerMain - pass thru plugin version
ShaneBeee Feb 15, 2026
eb67a49
ExprWorldTPS - add WorldTPS expression
ShaneBeee Feb 15, 2026
a809e0e
Merge branch 'master' into dev/feature
ShaneBeee Feb 15, 2026
a285c43
TypesItem - reorganize and fix up ItemContainer serializers
ShaneBeee Feb 15, 2026
8ec2a36
Add current TPS/MSPT expressions
ShaneBeee Feb 16, 2026
2cae5e4
ExprBlockTypeOfBlock - note for later
ShaneBeee Feb 16, 2026
7344e2b
EvtPlayerSwitchActiveSlot - add event
ShaneBeee Feb 16, 2026
2704225
TypesItem - add Page type (you went missing somehow)
ShaneBeee Feb 16, 2026
aa73716
ElementRegistration - fix structure count
ShaneBeee Feb 16, 2026
aa6fccd
HySkriptAddon - add some quick link methods to Hytale plugin stuff
ShaneBeee Feb 16, 2026
c46c906
More JavaDocs
ShaneBeee Feb 16, 2026
61636b8
ExprWorldTimeDurations - add time durations
ShaneBeee Feb 16, 2026
6661c56
ExprLocationOffset - add expression to offset a location
ShaneBeee Feb 16, 2026
6cdc8b2
ExprLocationOffset.sk - add test
ShaneBeee Feb 16, 2026
dfe2e56
ExprCoordinates - add coord expr
ShaneBeee Feb 16, 2026
767c0aa
ExprCoordinates.sk - add test
ShaneBeee Feb 16, 2026
e9d4f97
CondEntityIsAlive - add condition to check for life
ShaneBeee Feb 16, 2026
27e084a
Conditions - repackage by type
ShaneBeee Feb 16, 2026
e423d15
Conditions - rename
ShaneBeee Feb 16, 2026
2e45c88
build.gradle.kts - switch to skript-parser dev branch
ShaneBeee Feb 16, 2026
ce7ad94
DefaultFunctions - update to new function registration
ShaneBeee Feb 16, 2026
0920122
ExprInventoryAmountOfItems - add expr to count items in inventory
ShaneBeee Feb 16, 2026
c6b0e51
ExprItemStackQuantity - add expr for itemstack quantity
ShaneBeee Feb 16, 2026
f93d8e7
ExprInventoryAmountOfItems - change pattern
ShaneBeee Feb 16, 2026
848ed5d
ExprItemStackWithQuantity - new expr to get itemstack copy with quantity
ShaneBeee Feb 16, 2026
1ec8f43
DefaultFunctions - inventory functions
ShaneBeee Feb 17, 2026
aaf9a1f
build.gradle.kts - update to pre-release to make sure everything works
ShaneBeee Feb 17, 2026
a58c70e
ExprItemContainer - removed last pattern as hytale removed the method
ShaneBeee Feb 17, 2026
11e2008
EffShoot - add broken shoot effect
ShaneBeee Feb 17, 2026
52c35b0
Add some tameable stuff
ShaneBeee Feb 17, 2026
7eb4891
Add some tameable stuff - part 2
ShaneBeee Feb 17, 2026
bf7e233
build.gradle.kts - that wasn't supposed to get commited
ShaneBeee Feb 17, 2026
df5abb8
ExprItemStackName - expr for ittemstack name/description
ShaneBeee Feb 17, 2026
63c8e27
build.gradle.kts - update Hytale release version
ShaneBeee Feb 17, 2026
33e665f
manifest.json - remove ">=" for server version
ShaneBeee Feb 17, 2026
d6c568e
build.gradle.kts - OMG Shane stop commiting your test version
ShaneBeee Feb 17, 2026
63781e1
ExprHighestBlock - add highest block expression
ShaneBeee Feb 17, 2026
33e6c1a
JsonDocPrinter - use new function registration
ShaneBeee Feb 17, 2026
2827bd3
CondBlockIsSolid - add block is solid condition
ShaneBeee Feb 17, 2026
fa6759d
ExprLocationRotation - add location rotation
ShaneBeee Feb 18, 2026
648b828
ExprEntityHeadRotation - add
ShaneBeee Feb 18, 2026
1ae65fa
EntityUtils - add ensure
ShaneBeee Feb 18, 2026
d93767b
ExprEntityScale - add
ShaneBeee Feb 18, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .github/contributing.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ This way the team can discuss with you whether or not we want this in HySkript.
- Use descriptive commit messages
- Use descriptive PR titles
- Ensure you follow the code style of this project
- Do make sure you add tests and run the test to make sure it works.
- See the [Testing Guide](https://github.com/SkriptDev/HySkript/tree/master/src/test/README.md) for more information.

### Don't:
- Don't commit directly to `master`
Expand Down Expand Up @@ -60,3 +62,6 @@ This way the team can discuss with you whether or not we want this in HySkript.
- For expressions, please provide an example of using the getter as well as each changer you have applied.
- For all others, please provide at least one example per pattern.
- Please see other examples in HySkript for further inspiration.

### Tests:
See the [Testing Guide](https://github.com/SkriptDev/HySkript/tree/master/src/test/README.md) for more information.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,6 @@ bin/
### Mac OS ###
.DS_Store
**/.DS_Store

### Run Folder ###
run/
26 changes: 23 additions & 3 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,17 @@ java.sourceCompatibility = JavaVersion.VERSION_25

group = "com.github.SkriptDev"
val projectVersion = "1.0.0"
val hytaleVersion = "2026.02.06-aa1b071c2"
val hytaleVersion = "2026.02.17-255364b8e"
// You can find Hytale versions on their maven repo:
// https://maven.hytale.com/release/com/hypixel/hytale/Server/maven-metadata.xml
// https://maven.hytale.com/pre-release/com/hypixel/hytale/Server/maven-metadata.xml
// (Pre-releases shouldn't be used for production)

// Location of the Hytale Server Assets
// This is used in testing
// Change this to wherever you have it on your computer
val assetLocation = "/Users/ShaneBee/Desktop/Server/Hytale/Assets/Assets.zip"

repositories {
mavenCentral()
mavenLocal()
Expand All @@ -26,14 +31,20 @@ repositories {
dependencies {
compileOnly("com.hypixel.hytale:Server:${hytaleVersion}")
compileOnly("org.jetbrains:annotations:26.0.2")
implementation("com.github.SkriptDev:skript-parser:1.0.8") {
implementation("com.github.SkriptDev:skript-parser:dev~patch-SNAPSHOT") {
isTransitive = false
}
implementation("com.github.Zoltus:TinyMessage:2.0.1") {
isTransitive = false
}
}

// This is used to enable Gson in the test environment via HytaleServer
val testRunnerClasspath by configurations.creating {
extendsFrom(configurations.compileOnly.get())
isCanBeResolved = true
}

tasks {
register("server", Copy::class) {
dependsOn("jar")
Expand All @@ -42,6 +53,14 @@ tasks {
destinationDir = file("/Users/ShaneBee/Desktop/Server/Hytale/Creative/mods/")
}
}
register<JavaExec>("testRunner") {
dependsOn("jar")
group = "application"
mainClass.set("com.github.skriptdev.skript.api.skript.testing.TestRunnerMain")
args(hytaleVersion, projectVersion, assetLocation)

classpath = sourceSets["main"].runtimeClasspath + testRunnerClasspath
}
processResources {
filesNotMatching("assets/**") {
expand("pluginVersion" to projectVersion, "hytaleVersion" to hytaleVersion)
Expand Down Expand Up @@ -71,7 +90,8 @@ tasks {
options.encoding = Charsets.UTF_8.name()
exclude(
"com/github/skriptdev/skript/plugin/elements",
"com/github/skriptdev/skript/plugin/command"
"com/github/skriptdev/skript/plugin/command",
"com/github/skriptdev/skript/api/skript/testing/elements"
)
(options as StandardJavadocDocletOptions).links(
"https://javadoc.io/doc/org.jetbrains/annotations/latest/",
Expand Down
84 changes: 82 additions & 2 deletions src/main/java/com/github/skriptdev/skript/api/hytale/Block.java
Original file line number Diff line number Diff line change
@@ -1,22 +1,34 @@
package com.github.skriptdev.skript.api.hytale;

import com.github.skriptdev.skript.api.utils.Utils;
import com.github.skriptdev.skript.api.hytale.utils.StoreUtils;
import com.hypixel.hytale.component.CommandBuffer;
import com.hypixel.hytale.component.Ref;
import com.hypixel.hytale.component.Store;
import com.hypixel.hytale.math.util.ChunkUtil;
import com.hypixel.hytale.math.vector.Location;
import com.hypixel.hytale.math.vector.Vector3i;
import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockType;
import com.hypixel.hytale.server.core.asset.type.fluid.Fluid;
import com.hypixel.hytale.server.core.entity.LivingEntity;
import com.hypixel.hytale.server.core.inventory.ItemStack;
import com.hypixel.hytale.server.core.modules.blockhealth.BlockHealth;
import com.hypixel.hytale.server.core.modules.blockhealth.BlockHealthChunk;
import com.hypixel.hytale.server.core.modules.blockhealth.BlockHealthModule;
import com.hypixel.hytale.server.core.modules.interaction.BlockHarvestUtils;
import com.hypixel.hytale.server.core.universe.PlayerRef;
import com.hypixel.hytale.server.core.universe.Universe;
import com.hypixel.hytale.server.core.universe.world.World;
import com.hypixel.hytale.server.core.universe.world.chunk.ChunkColumn;
import com.hypixel.hytale.server.core.universe.world.chunk.WorldChunk;
import com.hypixel.hytale.server.core.universe.world.chunk.section.FluidSection;
import com.hypixel.hytale.server.core.universe.world.storage.ChunkStore;
import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.Map;
import java.util.function.Predicate;

/**
* Represents a block in a world.
* Hytale doesn't appear to have a representation of a block in the world.
Expand Down Expand Up @@ -137,7 +149,6 @@ public void setFluid(@NotNull Fluid fluid, @Nullable Integer level) {
if (fluidLevel <= 0) fluidLevel = (byte) fluid.getMaxFluidLevel();
}
fluidLevel = (byte) Math.clamp((int) fluidLevel, 0, fluid.getMaxFluidLevel());
Utils.log("Set fluid level to %s", fluidLevel);
fluidSection.setFluid(this.pos.getX(), this.pos.getY(), this.pos.getZ(), fluid, fluidLevel);
}
return chunk;
Expand All @@ -148,6 +159,75 @@ public void breakBlock(int settings) {
this.world.breakBlock(this.pos.getX(), this.pos.getY(), this.pos.getZ(), settings);
}

public void damage(@Nullable LivingEntity performer, @Nullable ItemStack itemStack, float damage) {
WorldChunk chunk = this.world.getChunk(ChunkUtil.indexChunkFromBlock(this.pos.getX(), this.pos.getZ()));
if (chunk == null) return;

Ref<ChunkStore> ref = chunk.getReference();
Store<ChunkStore> chunkStore = this.world.getChunkStore().getStore();
CommandBuffer<EntityStore> commandBuffer = StoreUtils.getCommandBuffer(this.world.getEntityStore().getStore());

if (performer == null) {
BlockHarvestUtils.performBlockDamage(
this.pos,
null,
null,
damage,
0,
ref,
commandBuffer,
chunkStore);
} else {
BlockHarvestUtils.performBlockDamage(
performer,
performer.getReference(),
this.pos,
itemStack,
null,
null, // TODO figure out how to get this
false,
damage,
0,
ref,
commandBuffer,
chunkStore);
}
}

public float getBlockHealth() {
WorldChunk chunk = this.world.getChunk(ChunkUtil.indexChunkFromBlock(this.pos.getX(), this.pos.getZ()));
if (chunk == null) return 0;

Ref<ChunkStore> ref = chunk.getReference();
Store<ChunkStore> chunkStore = this.world.getChunkStore().getStore();

BlockHealthChunk component = chunkStore.getComponent(ref, BlockHealthModule.get().getBlockHealthChunkComponentType());
if (component == null) return 0;

return component.getBlockHealth(this.pos);
}

public void setBlockHealth(float health) {
WorldChunk chunk = this.world.getChunk(ChunkUtil.indexChunkFromBlock(this.pos.getX(), this.pos.getZ()));
if (chunk == null) return;

Ref<ChunkStore> ref = chunk.getReference();
Store<ChunkStore> chunkStore = this.world.getChunkStore().getStore();
BlockHealthChunk component = chunkStore.getComponent(ref, BlockHealthModule.get().getBlockHealthChunkComponentType());
if (component == null) return;

Map<Vector3i, BlockHealth> blockHealthMap = component.getBlockHealthMap();
BlockHealth blockHealth = blockHealthMap.getOrDefault(this.pos, new BlockHealth());
blockHealth.setHealth(health);
blockHealthMap.put(this.pos, blockHealth);

if (!blockHealth.isDestroyed()) {
Predicate<PlayerRef> filter = (player) -> true;
world.getNotificationHandler().updateBlockDamage(this.pos.getX(), this.pos.getY(),
this.pos.getZ(), blockHealth.getHealth(), health, filter);
}
}

public @NotNull World getWorld() {
return this.world;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.github.skriptdev.skript.api.hytale.utils;

import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockType;
import com.hypixel.hytale.server.core.asset.type.environment.config.Environment;
import com.hypixel.hytale.server.core.asset.type.item.config.Item;
import com.hypixel.hytale.server.core.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
Expand Down Expand Up @@ -42,4 +43,24 @@ public class AssetStoreUtils {
return null;
}

/**
* Get the AssetStore index of an Environment
*
* @param environment Environment to get index from
* @return Index from Environment
*/
public static int getEnvironmentIndex(Environment environment) {
return Environment.getAssetMap().getIndex(environment.getId());
}

/**
* Get an Environment from its AssetStore index.
*
* @param index Index to grab Environment from
* @return Environment from index, or null if not found
*/
public static Environment getEnvironment(int index) {
return Environment.getAssetMap().getAsset(index);
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.github.skriptdev.skript.api.hytale.utils;

import com.github.skriptdev.skript.api.skript.registration.NPCRegistry;
import com.github.skriptdev.skript.api.utils.Utils;
import com.hypixel.hytale.component.AddReason;
import com.hypixel.hytale.component.Component;
import com.hypixel.hytale.component.ComponentType;
Expand All @@ -20,6 +22,9 @@
import com.hypixel.hytale.server.core.modules.entitystats.EntityStatsModule;
import com.hypixel.hytale.server.core.universe.world.World;
import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
import com.hypixel.hytale.server.npc.entities.NPCEntity;
import com.hypixel.hytale.server.npc.role.Role;
import com.hypixel.hytale.server.npc.systems.RoleChangeSystem;
import io.github.syst3ms.skriptparser.util.Pair;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
Expand Down Expand Up @@ -99,7 +104,7 @@ public static void setNameplateName(Entity entity, @Nullable String name) {
}

/**
* Get a component from an Entity
* Get a component from an Entity.
*
* @param entity Entity to get component from
* @param type Component type to get
Expand All @@ -116,6 +121,26 @@ public static void setNameplateName(Entity entity, @Nullable String name) {
return store.getComponent(reference, type);
}

/**
* Get a component from an Entity or create it if not present.
*
* @param entity Entity to get component from
* @param type Component type to get
* @param <ECS_TYPE> EntityStore Type
* @param <T> Type of returned component
* @return Component from entity if available otherwise will create/add a new one
*/
@SuppressWarnings("unchecked")
public static <ECS_TYPE, T extends Component<ECS_TYPE>> @NotNull T ensureAndGetComponent(Entity entity, ComponentType<ECS_TYPE, T> type) {
Ref<ECS_TYPE> reference = (Ref<ECS_TYPE>) entity.getReference();
if (reference == null) {
throw new IllegalStateException("Entity '" + entity + "' does not have a reference");
}

Store<ECS_TYPE> store = reference.getStore();
return store.ensureAndGetComponent(reference, type);
}

/**
* Get the EntityStatMap component of an entity.
*
Expand Down Expand Up @@ -173,4 +198,54 @@ public static void setNameplateName(Entity entity, @Nullable String name) {
return new Pair<>(com.hypixel.hytale.server.core.entity.EntityUtils.getEntity(itemEntityHolder), itemComponent);
}

public static boolean isTameable(NPCEntity npcEntity) {
Role role = npcEntity.getRole();
if (role == null) return false;

String roleName = role.getRoleName();
if (roleName.contains("Tamed_")) {
return true;
}
// I know this is hacky, but Hytale doesn't have any API for taming
// Maybe we'll get lucky and Hytale will create API for this
NPCRegistry.NPCRole parse = NPCRegistry.parse("tamed_" + roleName);
return parse != null;
}

public static boolean isTamed(NPCEntity npcEntity) {
Role role = npcEntity.getRole();
if (role == null) return false;

// I know this is hacky, but Hytale doesn't have any API for taming
// Maybe we'll get lucky and Hytale will create API for this
String roleName = role.getRoleName();
return roleName.startsWith("Tamed_");
}

public static void setTamed(NPCEntity npcEntity, boolean tamed) {
if (!isTameable(npcEntity)) {
return;
}
if ((tamed && isTamed(npcEntity)) || (!tamed && !isTamed(npcEntity))) {
return;
}
Ref<EntityStore> reference = npcEntity.getReference();
if (reference == null) return;

Store<EntityStore> store = reference.getStore();

// I know this is hacky, but Hytale doesn't have any API for taming
// Maybe we'll get lucky and Hytale will create API for this
Role currentRole = npcEntity.getRole();
if (currentRole == null || currentRole.isRoleChangeRequested()) return;

String roleName = currentRole.getRoleName();
roleName = tamed ? "Tamed_" + roleName : roleName.replace("Tamed_", "");

NPCRegistry.NPCRole parse = NPCRegistry.parse(roleName);

Utils.log("Changing role to %s", parse.name());
RoleChangeSystem.requestRoleChange(reference, currentRole, parse.index(), true, store);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
* Utilities for a {@link Store Hytale Store}
*/
public class StoreUtils {

@SuppressWarnings("unchecked")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/**
* Utility classes for Hytale.
*/
package com.github.skriptdev.skript.api.hytale.utils;
Loading