2026.02.11-255364b8e

This commit is contained in:
Intege-rs
2026-02-11 18:06:52 -05:00
parent 8988b1dc65
commit 4dcc723c9c
550 changed files with 12847 additions and 5414 deletions

View File

@@ -2,7 +2,7 @@ package com.hypixel.hytale.builtin.adventure.camera.asset.camerashake;
import com.hypixel.hytale.assetstore.map.IndexedAssetMap;
import com.hypixel.hytale.protocol.CachedPacket;
import com.hypixel.hytale.protocol.Packet;
import com.hypixel.hytale.protocol.ToClientPacket;
import com.hypixel.hytale.protocol.UpdateType;
import com.hypixel.hytale.protocol.packets.assets.UpdateCameraShake;
import com.hypixel.hytale.server.core.asset.packet.SimpleAssetPacketGenerator;
@@ -14,17 +14,17 @@ import javax.annotation.Nonnull;
public class CameraShakePacketGenerator extends SimpleAssetPacketGenerator<String, CameraShake, IndexedAssetMap<String, CameraShake>> {
@Nonnull
public Packet generateInitPacket(@Nonnull IndexedAssetMap<String, CameraShake> assetMap, @Nonnull Map<String, CameraShake> assets) {
public ToClientPacket generateInitPacket(@Nonnull IndexedAssetMap<String, CameraShake> assetMap, @Nonnull Map<String, CameraShake> assets) {
return toCachedPacket(UpdateType.Init, assetMap, assets);
}
@Nonnull
protected Packet generateUpdatePacket(@Nonnull IndexedAssetMap<String, CameraShake> assetMap, @Nonnull Map<String, CameraShake> loadedAssets) {
protected ToClientPacket generateUpdatePacket(@Nonnull IndexedAssetMap<String, CameraShake> assetMap, @Nonnull Map<String, CameraShake> loadedAssets) {
return toCachedPacket(UpdateType.AddOrUpdate, assetMap, loadedAssets);
}
@Nonnull
protected Packet generateRemovePacket(@Nonnull IndexedAssetMap<String, CameraShake> assetMap, @Nonnull Set<String> removed) {
protected ToClientPacket generateRemovePacket(@Nonnull IndexedAssetMap<String, CameraShake> assetMap, @Nonnull Set<String> removed) {
Int2ObjectOpenHashMap<com.hypixel.hytale.protocol.CameraShake> profiles = new Int2ObjectOpenHashMap<>();
for (String key : removed) {
@@ -39,7 +39,7 @@ public class CameraShakePacketGenerator extends SimpleAssetPacketGenerator<Strin
}
@Nonnull
protected static Packet toCachedPacket(
protected static ToClientPacket toCachedPacket(
@Nonnull UpdateType type, @Nonnull IndexedAssetMap<String, CameraShake> assetMap, @Nonnull Map<String, CameraShake> assets
) {
Int2ObjectOpenHashMap<com.hypixel.hytale.protocol.CameraShake> profiles = new Int2ObjectOpenHashMap<>();

View File

@@ -3,7 +3,7 @@ package com.hypixel.hytale.builtin.adventure.camera.asset.viewbobbing;
import com.hypixel.hytale.assetstore.AssetMap;
import com.hypixel.hytale.protocol.CachedPacket;
import com.hypixel.hytale.protocol.MovementType;
import com.hypixel.hytale.protocol.Packet;
import com.hypixel.hytale.protocol.ToClientPacket;
import com.hypixel.hytale.protocol.UpdateType;
import com.hypixel.hytale.protocol.packets.assets.UpdateViewBobbing;
import com.hypixel.hytale.server.core.asset.packet.SimpleAssetPacketGenerator;
@@ -16,19 +16,19 @@ import javax.annotation.Nonnull;
public class ViewBobbingPacketGenerator extends SimpleAssetPacketGenerator<MovementType, ViewBobbing, AssetMap<MovementType, ViewBobbing>> {
@Nonnull
@Override
public Packet generateInitPacket(AssetMap<MovementType, ViewBobbing> assetMap, @Nonnull Map<MovementType, ViewBobbing> assets) {
public ToClientPacket generateInitPacket(AssetMap<MovementType, ViewBobbing> assetMap, @Nonnull Map<MovementType, ViewBobbing> assets) {
return toCachedPacket(UpdateType.Init, assets);
}
@Nonnull
@Override
protected Packet generateUpdatePacket(AssetMap<MovementType, ViewBobbing> assetMap, @Nonnull Map<MovementType, ViewBobbing> loadedAssets) {
protected ToClientPacket generateUpdatePacket(AssetMap<MovementType, ViewBobbing> assetMap, @Nonnull Map<MovementType, ViewBobbing> loadedAssets) {
return toCachedPacket(UpdateType.AddOrUpdate, loadedAssets);
}
@Nonnull
@Override
protected Packet generateRemovePacket(AssetMap<MovementType, ViewBobbing> assetMap, @Nonnull Set<MovementType> removed) {
protected ToClientPacket generateRemovePacket(AssetMap<MovementType, ViewBobbing> assetMap, @Nonnull Set<MovementType> removed) {
UpdateViewBobbing packet = new UpdateViewBobbing();
packet.type = UpdateType.Remove;
packet.profiles = new EnumMap<>(MovementType.class);
@@ -41,7 +41,7 @@ public class ViewBobbingPacketGenerator extends SimpleAssetPacketGenerator<Movem
}
@Nonnull
protected static Packet toCachedPacket(@Nonnull UpdateType type, @Nonnull Map<MovementType, ViewBobbing> assets) {
protected static ToClientPacket toCachedPacket(@Nonnull UpdateType type, @Nonnull Map<MovementType, ViewBobbing> assets) {
UpdateViewBobbing packet = new UpdateViewBobbing();
packet.type = type;
packet.profiles = new EnumMap<>(MovementType.class);

View File

@@ -172,7 +172,7 @@ public class FarmingUtil {
}
}
public static void harvest(
public static boolean harvest(
@Nonnull World world,
@Nonnull ComponentAccessor<EntityStore> componentAccessor,
@Nonnull Ref<EntityStore> ref,
@@ -180,9 +180,9 @@ public class FarmingUtil {
int rotationIndex,
@Nonnull Vector3i blockPosition
) {
if (world.getGameplayConfig().getWorldConfig().isBlockGatheringAllowed()) {
harvest0(componentAccessor, ref, blockType, rotationIndex, blockPosition);
}
return world.getGameplayConfig().getWorldConfig().isBlockGatheringAllowed()
? harvest0(componentAccessor, ref, blockType, rotationIndex, blockPosition)
: false;
}
@Nullable
@@ -212,24 +212,19 @@ public class FarmingUtil {
@Nonnull Vector3i blockPosition
) {
FarmingData farmingConfig = blockType.getFarming();
boolean isFarmable = true;
if (farmingConfig == null || farmingConfig.getStages() == null) {
return false;
} else if (blockType.getGathering().getHarvest() == null) {
isFarmable = false;
}
if (blockType.getGathering().getHarvest() == null) {
return false;
} else {
World world = store.getExternalData().getWorld();
Vector3d centerPosition = new Vector3d();
blockType.getBlockCenter(rotationIndex, centerPosition);
centerPosition.add(blockPosition);
if (farmingConfig.getStageSetAfterHarvest() == null) {
giveDrops(store, ref, centerPosition, blockType);
WorldChunk chunk = world.getChunkIfInMemory(ChunkUtil.indexChunkFromBlock(blockPosition.x, blockPosition.z));
if (chunk != null) {
chunk.breakBlock(blockPosition.x, blockPosition.y, blockPosition.z);
}
return true;
} else {
if (isFarmable && farmingConfig.getStageSetAfterHarvest() != null) {
giveDrops(store, ref, centerPosition, blockType);
Map<String, FarmingStageData[]> stageSets = farmingConfig.getStages();
FarmingStageData[] stages = stageSets.get(farmingConfig.getStartingStageSet());
@@ -307,6 +302,14 @@ public class FarmingUtil {
return false;
}
}
} else {
giveDrops(store, ref, centerPosition, blockType);
WorldChunk chunk = world.getChunkIfInMemory(ChunkUtil.indexChunkFromBlock(blockPosition.x, blockPosition.z));
if (chunk != null) {
chunk.breakBlock(blockPosition.x, blockPosition.y, blockPosition.z);
}
return true;
}
}
}

View File

@@ -1,11 +1,14 @@
package com.hypixel.hytale.builtin.adventure.farming.interactions;
import com.hypixel.hytale.builtin.adventure.farming.FarmingUtil;
import com.hypixel.hytale.codec.Codec;
import com.hypixel.hytale.codec.KeyedCodec;
import com.hypixel.hytale.codec.builder.BuilderCodec;
import com.hypixel.hytale.component.CommandBuffer;
import com.hypixel.hytale.component.Ref;
import com.hypixel.hytale.math.util.ChunkUtil;
import com.hypixel.hytale.math.vector.Vector3i;
import com.hypixel.hytale.protocol.InteractionState;
import com.hypixel.hytale.protocol.InteractionType;
import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockType;
import com.hypixel.hytale.server.core.entity.InteractionContext;
@@ -27,7 +30,16 @@ public class HarvestCropInteraction extends SimpleBlockInteraction {
HarvestCropInteraction.class, HarvestCropInteraction::new, SimpleBlockInteraction.CODEC
)
.documentation("Harvests the resources from the target farmable block.")
.<Boolean>appendInherited(
new KeyedCodec<>("RequireNotBroken", Codec.BOOLEAN),
(interaction, s) -> interaction.requireNotBroken = s,
interaction -> interaction.requireNotBroken,
(interaction, parent) -> interaction.requireNotBroken = parent.requireNotBroken
)
.documentation("If true, the interaction will fail if the held item is broken (durability = 0).")
.add()
.build();
protected boolean requireNotBroken = false;
@Override
protected void interactWithBlock(
@@ -39,25 +51,31 @@ public class HarvestCropInteraction extends SimpleBlockInteraction {
@Nonnull Vector3i targetBlock,
@Nonnull CooldownHandler cooldownHandler
) {
Ref<EntityStore> ref = context.getEntity();
ChunkStore chunkStore = world.getChunkStore();
long chunkIndex = ChunkUtil.indexChunkFromBlock(targetBlock.x, targetBlock.z);
Ref<ChunkStore> chunkRef = chunkStore.getChunkReference(chunkIndex);
if (chunkRef != null && chunkRef.isValid()) {
BlockChunk blockChunkComponent = chunkStore.getStore().getComponent(chunkRef, BlockChunk.getComponentType());
if (this.requireNotBroken && itemInHand != null && itemInHand.isBroken()) {
context.getState().state = InteractionState.Failed;
} else {
Ref<EntityStore> ref = context.getEntity();
ChunkStore chunkStore = world.getChunkStore();
long chunkIndex = ChunkUtil.indexChunkFromBlock(targetBlock.x, targetBlock.z);
Ref<ChunkStore> chunkRef = chunkStore.getChunkReference(chunkIndex);
if (chunkRef != null && chunkRef.isValid()) {
BlockChunk blockChunkComponent = chunkStore.getStore().getComponent(chunkRef, BlockChunk.getComponentType());
assert blockChunkComponent != null;
assert blockChunkComponent != null;
BlockSection blockSection = blockChunkComponent.getSectionAtBlockY(targetBlock.y);
if (blockSection != null) {
WorldChunk worldChunkComponent = chunkStore.getStore().getComponent(chunkRef, WorldChunk.getComponentType());
BlockSection blockSection = blockChunkComponent.getSectionAtBlockY(targetBlock.y);
if (blockSection != null) {
WorldChunk worldChunkComponent = chunkStore.getStore().getComponent(chunkRef, WorldChunk.getComponentType());
assert worldChunkComponent != null;
assert worldChunkComponent != null;
BlockType blockType = worldChunkComponent.getBlockType(targetBlock);
if (blockType != null) {
int rotationIndex = blockSection.getRotationIndex(targetBlock.x, targetBlock.y, targetBlock.z);
FarmingUtil.harvest(world, commandBuffer, ref, blockType, rotationIndex, targetBlock);
BlockType blockType = worldChunkComponent.getBlockType(targetBlock);
if (blockType != null) {
int rotationIndex = blockSection.getRotationIndex(targetBlock.x, targetBlock.y, targetBlock.z);
if (!FarmingUtil.harvest(world, commandBuffer, ref, blockType, rotationIndex, targetBlock)) {
context.getState().state = InteractionState.Failed;
}
}
}
}
}

View File

@@ -35,7 +35,6 @@ import com.hypixel.hytale.server.core.modules.entity.component.TransformComponen
import com.hypixel.hytale.server.core.modules.entity.item.ItemComponent;
import com.hypixel.hytale.server.core.modules.entity.item.PickupItemComponent;
import com.hypixel.hytale.server.core.modules.entity.tracker.NetworkId;
import com.hypixel.hytale.server.core.modules.i18n.I18nModule;
import com.hypixel.hytale.server.core.universe.PlayerRef;
import com.hypixel.hytale.server.core.universe.world.World;
import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
@@ -62,12 +61,6 @@ public class NPCMemory extends Memory {
.add()
.append(new KeyedCodec<>("TranslationKey", Codec.STRING), (npcMemory, s) -> npcMemory.memoryTitleKey = s, npcMemory -> npcMemory.memoryTitleKey)
.add()
.append(
new KeyedCodec<>("IsMemoriesNameOverridden", Codec.BOOLEAN),
(npcMemory, aBoolean) -> npcMemory.isMemoriesNameOverridden = aBoolean,
npcMemory -> npcMemory.isMemoriesNameOverridden
)
.add()
.append(
new KeyedCodec<>("CapturedTimestamp", Codec.LONG),
(npcMemory, aDouble) -> npcMemory.capturedTimestamp = aDouble,
@@ -86,10 +79,8 @@ public class NPCMemory extends Memory {
npcMemory -> npcMemory.foundLocationGeneralNameKey
)
.add()
.afterDecode(NPCMemory::processConfig)
.build();
private String npcRole;
private boolean isMemoriesNameOverridden;
private long capturedTimestamp;
private String foundLocationZoneNameKey;
private String foundLocationGeneralNameKey;
@@ -98,11 +89,9 @@ public class NPCMemory extends Memory {
private NPCMemory() {
}
public NPCMemory(@Nonnull String npcRole, @Nonnull String nameTranslationKey, boolean isMemoriesNameOverridden) {
public NPCMemory(@Nonnull String npcRole, @Nonnull String nameTranslationKey) {
this.npcRole = npcRole;
this.memoryTitleKey = nameTranslationKey;
this.isMemoriesNameOverridden = isMemoriesNameOverridden;
this.processConfig();
}
@Override
@@ -128,19 +117,6 @@ public class NPCMemory extends Memory {
return "UI/Custom/Pages/Memories/npcs/" + this.npcRole + ".png";
}
public void processConfig() {
if (this.isMemoriesNameOverridden) {
this.memoryTitleKey = "server.npcRoles." + this.npcRole + ".name";
if (I18nModule.get().getMessage("en-US", this.memoryTitleKey) == null) {
this.memoryTitleKey = "server.memories.names." + this.npcRole;
}
}
if (this.memoryTitleKey == null || this.memoryTitleKey.isEmpty()) {
this.memoryTitleKey = "server.npcRoles." + this.npcRole + ".name";
}
}
@Nonnull
@Override
public Message getUndiscoveredTooltipText() {
@@ -177,15 +153,14 @@ public class NPCMemory extends Memory {
return false;
} else {
NPCMemory npcMemory = (NPCMemory)o;
return this.isMemoriesNameOverridden == npcMemory.isMemoriesNameOverridden && Objects.equals(this.npcRole, npcMemory.npcRole);
return Objects.equals(this.npcRole, npcMemory.npcRole);
}
}
@Override
public int hashCode() {
int result = super.hashCode();
result = 31 * result + Objects.hashCode(this.npcRole);
return 31 * result + Boolean.hashCode(this.isMemoriesNameOverridden);
return 31 * result + Objects.hashCode(this.npcRole);
}
@Nonnull
@@ -193,8 +168,6 @@ public class NPCMemory extends Memory {
public String toString() {
return "NPCMemory{npcRole='"
+ this.npcRole
+ "', isMemoriesNameOverride="
+ this.isMemoriesNameOverridden
+ "', capturedTimestamp="
+ this.capturedTimestamp
+ "', foundLocationZoneNameKey='"
@@ -271,46 +244,41 @@ public class NPCMemory extends Memory {
if (npcComponent != null) {
Role role = npcComponent.getRole();
if (role != null && role.isMemory()) {
temp.isMemoriesNameOverridden = role.isMemoriesNameOverriden();
temp.npcRole = temp.isMemoriesNameOverridden ? role.getMemoriesNameOverride() : npcComponent.getRoleName();
String memoriesNameOverride = role.getMemoriesNameOverride();
temp.npcRole = memoriesNameOverride != null && !memoriesNameOverride.isEmpty() ? memoriesNameOverride : npcComponent.getRoleName();
temp.memoryTitleKey = role.getNameTranslationKey();
temp.capturedTimestamp = System.currentTimeMillis();
temp.foundLocationGeneralNameKey = foundLocationZoneNameKey;
if (!memoriesPlugin.hasRecordedMemory(temp)) {
temp.processConfig();
if (playerMemoriesComponent.recordMemory(temp)) {
NotificationUtil.sendNotification(
playerRefComponent.getPacketHandler(),
Message.translation("server.memories.general.collected").param("memoryTitle", Message.translation(temp.getTitle())),
null,
"NotificationIcons/MemoriesIcon.png"
);
temp = new NPCMemory();
TransformComponent npcTransformComponent = commandBuffer.getComponent(npcRef, TransformComponent.getComponentType());
if (npcTransformComponent != null) {
MemoriesGameplayConfig memoriesGameplayConfig = MemoriesGameplayConfig.get(
store.getExternalData().getWorld().getGameplayConfig()
);
if (memoriesGameplayConfig != null) {
ItemStack memoryItemStack = new ItemStack(memoriesGameplayConfig.getMemoriesCatchItemId());
Vector3d memoryItemHolderPosition = npcTransformComponent.getPosition().clone();
BoundingBox boundingBoxComponent = commandBuffer.getComponent(npcRef, BoundingBox.getComponentType());
if (boundingBoxComponent != null) {
memoryItemHolderPosition.y = memoryItemHolderPosition.y + boundingBoxComponent.getBoundingBox().middleY();
}
Holder<EntityStore> memoryItemHolder = ItemComponent.generatePickedUpItem(
memoryItemStack, memoryItemHolderPosition, commandBuffer, ref
);
float memoryCatchItemLifetimeS = 0.62F;
PickupItemComponent pickupItemComponent = memoryItemHolder.getComponent(PickupItemComponent.getComponentType());
assert pickupItemComponent != null;
pickupItemComponent.setInitialLifeTime(0.62F);
commandBuffer.addEntity(memoryItemHolder, AddReason.SPAWN);
displayCatchEntityParticles(memoriesGameplayConfig, memoryItemHolderPosition, npcRef, commandBuffer);
if (!memoriesPlugin.hasRecordedMemory(temp) && playerMemoriesComponent.recordMemory(temp)) {
NotificationUtil.sendNotification(
playerRefComponent.getPacketHandler(),
Message.translation("server.memories.general.collected").param("memoryTitle", Message.translation(temp.getTitle())),
null,
"NotificationIcons/MemoriesIcon.png"
);
temp = new NPCMemory();
TransformComponent npcTransformComponent = commandBuffer.getComponent(npcRef, TransformComponent.getComponentType());
if (npcTransformComponent != null) {
MemoriesGameplayConfig memoriesGameplayConfig = MemoriesGameplayConfig.get(store.getExternalData().getWorld().getGameplayConfig());
if (memoriesGameplayConfig != null) {
ItemStack memoryItemStack = new ItemStack(memoriesGameplayConfig.getMemoriesCatchItemId());
Vector3d memoryItemHolderPosition = npcTransformComponent.getPosition().clone();
BoundingBox boundingBoxComponent = commandBuffer.getComponent(npcRef, BoundingBox.getComponentType());
if (boundingBoxComponent != null) {
memoryItemHolderPosition.y = memoryItemHolderPosition.y + boundingBoxComponent.getBoundingBox().middleY();
}
Holder<EntityStore> memoryItemHolder = ItemComponent.generatePickedUpItem(
memoryItemStack, memoryItemHolderPosition, commandBuffer, ref
);
float memoryCatchItemLifetimeS = 0.62F;
PickupItemComponent pickupItemComponent = memoryItemHolder.getComponent(PickupItemComponent.getComponentType());
assert pickupItemComponent != null;
pickupItemComponent.setInitialLifeTime(0.62F);
commandBuffer.addEntity(memoryItemHolder, AddReason.SPAWN);
displayCatchEntityParticles(memoriesGameplayConfig, memoryItemHolderPosition, npcRef, commandBuffer);
}
}
}

View File

@@ -42,9 +42,9 @@ public class NPCMemoryProvider extends MemoryProvider<NPCMemory> {
String translationKey = getNPCNameTranslationKey(builder);
NPCMemory memory;
if (memoriesNameOverride != null && !memoriesNameOverride.isEmpty()) {
memory = new NPCMemory(memoriesNameOverride, translationKey, true);
memory = new NPCMemory(memoriesNameOverride, translationKey);
} else {
memory = new NPCMemory(builderInfo.getKeyName(), translationKey, false);
memory = new NPCMemory(builderInfo.getKeyName(), translationKey);
}
allMemories.computeIfAbsent(category, s -> new HashSet<>()).add(memory);

View File

@@ -101,11 +101,11 @@ public class MemoriesPage extends InteractiveCustomUIPage<MemoriesPage.PageEvent
commandBuilder.set(selector + "#TotalMemoryCountComplete.Text", String.valueOf(memoriesInCategory.size()));
boolean isCategoryComplete = recordedMemoriesCount == memoriesInCategory.size();
if (isCategoryComplete) {
commandBuilder.set(selector + "#CategoryIcon.Background", "Pages/Memories/categories/" + category + "Complete.png");
commandBuilder.set(selector + "#CategoryIcon.AssetPath", "UI/Custom/Pages/Memories/categories/" + category + "Complete.png");
commandBuilder.set(selector + "#CompleteCategoryBackground.Visible", true);
commandBuilder.set(selector + "#CompleteCategoryCounter.Visible", true);
} else {
commandBuilder.set(selector + "#CategoryIcon.Background", "Pages/Memories/categories/" + category + ".png");
commandBuilder.set(selector + "#CategoryIcon.AssetPath", "UI/Custom/Pages/Memories/categories/" + category + ".png");
commandBuilder.set(selector + "#NotCompleteCategoryCounter.Visible", true);
}

View File

@@ -854,6 +854,8 @@ public class ObjectivePlugin extends JavaPlugin {
oldModel.getGradientId(),
oldModel.getEyeHeight(),
oldModel.getCrouchOffset(),
oldModel.getSittingOffset(),
oldModel.getSleepingOffset(),
oldModel.getAnimationSetMap(),
oldModel.getCamera(),
oldModel.getLight(),

View File

@@ -177,6 +177,8 @@ public class ObjectiveLocationMarkerSystems {
model.getGradientId(),
model.getEyeHeight(),
model.getCrouchOffset(),
model.getSittingOffset(),
model.getSleepingOffset(),
model.getAnimationSetMap(),
model.getCamera(),
model.getLight(),

View File

@@ -242,7 +242,7 @@ public abstract class ObjectiveTask implements NetworkSerializer<Objective, com.
private void shutdownEventRegistry() {
if (this.eventRegistry != null) {
this.eventRegistry.shutdown();
this.eventRegistry.shutdownAndCleanup(true);
this.eventRegistry = null;
}
}

View File

@@ -6,6 +6,7 @@ import com.hypixel.hytale.builtin.adventure.teleporter.interaction.server.UsedTe
import com.hypixel.hytale.builtin.adventure.teleporter.page.TeleporterSettingsPageSupplier;
import com.hypixel.hytale.builtin.adventure.teleporter.system.ClearUsedTeleporterSystem;
import com.hypixel.hytale.builtin.adventure.teleporter.system.CreateWarpWhenTeleporterPlacedSystem;
import com.hypixel.hytale.builtin.adventure.teleporter.system.TurnOffTeleportersSystem;
import com.hypixel.hytale.builtin.teleport.TeleportPlugin;
import com.hypixel.hytale.component.AddReason;
import com.hypixel.hytale.component.CommandBuffer;
@@ -61,11 +62,13 @@ public class TeleporterPlugin extends JavaPlugin {
ComponentType<EntityStore, PendingTeleport> pendingTeleportComponentType = PendingTeleport.getComponentType();
chunkStoreRegistry.registerSystem(new TeleporterPlugin.TeleporterOwnedWarpRefChangeSystem(this.teleporterComponentType));
chunkStoreRegistry.registerSystem(new TeleporterPlugin.TeleporterOwnedWarpRefSystem(this.teleporterComponentType));
chunkStoreRegistry.registerSystem(
new CreateWarpWhenTeleporterPlacedSystem(
placedByInteractionComponentType, this.teleporterComponentType, blockStateInfoComponentType, playerRefComponentType
)
);
chunkStoreRegistry.registerSystem(new TurnOffTeleportersSystem());
this.getChunkStoreRegistry()
.registerSystem(
new CreateWarpWhenTeleporterPlacedSystem(
placedByInteractionComponentType, this.teleporterComponentType, blockStateInfoComponentType, playerRefComponentType
)
);
this.usedTeleporterComponentType = entityStoreRegistry.registerComponent(UsedTeleporter.class, UsedTeleporter::new);
entityStoreRegistry.registerSystem(
new ClearUsedTeleporterSystem(
@@ -151,18 +154,6 @@ public class TeleporterPlugin extends JavaPlugin {
public void onEntityAdded(
@Nonnull Ref<ChunkStore> ref, @Nonnull AddReason reason, @Nonnull Store<ChunkStore> store, @Nonnull CommandBuffer<ChunkStore> commandBuffer
) {
switch (reason) {
case LOAD:
Teleporter teleporterComponent = commandBuffer.getComponent(ref, this.teleporterComponentType);
if (teleporterComponent == null) {
return;
} else {
String ownedWarp = teleporterComponent.getOwnedWarp();
if (ownedWarp != null && !ownedWarp.isEmpty() && !TeleportPlugin.get().getWarps().containsKey(ownedWarp.toLowerCase())) {
}
}
case SPAWN:
}
}
@Override

View File

@@ -44,6 +44,8 @@ public class Teleporter implements Component<ChunkStore> {
.documentation("The ID of the Word list to select default warp names from")
.add()
.build();
public static final String ACTIVATE_STATE = "Active";
public static final String INACTIVE_STATE = "default";
@Nullable
private UUID worldUuid;
@Nullable

View File

@@ -2,6 +2,7 @@ package com.hypixel.hytale.builtin.adventure.teleporter.page;
import com.hypixel.hytale.builtin.adventure.teleporter.component.Teleporter;
import com.hypixel.hytale.builtin.adventure.teleporter.system.CreateWarpWhenTeleporterPlacedSystem;
import com.hypixel.hytale.builtin.adventure.teleporter.system.TurnOffTeleportersSystem;
import com.hypixel.hytale.builtin.adventure.teleporter.util.CannedWarpNames;
import com.hypixel.hytale.builtin.teleport.TeleportPlugin;
import com.hypixel.hytale.builtin.teleport.Warp;
@@ -11,13 +12,11 @@ import com.hypixel.hytale.codec.builder.BuilderCodec;
import com.hypixel.hytale.codec.codecs.EnumCodec;
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.Transform;
import com.hypixel.hytale.protocol.packets.interface_.CustomPageLifetime;
import com.hypixel.hytale.protocol.packets.interface_.CustomUIEventBindingType;
import com.hypixel.hytale.protocol.packets.interface_.Page;
import com.hypixel.hytale.server.core.Message;
import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockType;
import com.hypixel.hytale.server.core.entity.entities.Player;
import com.hypixel.hytale.server.core.entity.entities.player.pages.InteractiveCustomUIPage;
import com.hypixel.hytale.server.core.modules.block.BlockModule;
@@ -34,6 +33,7 @@ import com.hypixel.hytale.server.core.universe.world.storage.ChunkStore;
import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@@ -43,16 +43,11 @@ public class TeleporterSettingsPage extends InteractiveCustomUIPage<TeleporterSe
@Nonnull
private final Ref<ChunkStore> blockRef;
private final TeleporterSettingsPage.Mode mode;
@Nullable
private final String activeState;
public TeleporterSettingsPage(
@Nonnull PlayerRef playerRef, @Nonnull Ref<ChunkStore> blockRef, TeleporterSettingsPage.Mode mode, @Nullable String activeState
) {
public TeleporterSettingsPage(@Nonnull PlayerRef playerRef, @Nonnull Ref<ChunkStore> blockRef, TeleporterSettingsPage.Mode mode) {
super(playerRef, CustomPageLifetime.CanDismissOrCloseThroughInteraction, TeleporterSettingsPage.PageEventData.CODEC);
this.blockRef = blockRef;
this.mode = mode;
this.activeState = activeState;
}
@Override
@@ -182,10 +177,6 @@ public class TeleporterSettingsPage extends InteractiveCustomUIPage<TeleporterSe
assert worldChunkComponent != null;
int index = blockStateInfo.getIndex();
int targetX = ChunkUtil.xFromBlockInColumn(index);
int targetY = ChunkUtil.yFromBlockInColumn(index);
int targetZ = ChunkUtil.zFromBlockInColumn(index);
Teleporter teleporterComponent = this.blockRef.getStore().getComponent(this.blockRef, Teleporter.getComponentType());
if (teleporterComponent == null) {
playerComponent.getPageManager().setPage(ref, store, Page.None);
@@ -227,6 +218,8 @@ public class TeleporterSettingsPage extends InteractiveCustomUIPage<TeleporterSe
}
playerComponent.getPageManager().setPage(ref, store, Page.None);
String ownedWarpBefore = teleporterComponent.getOwnedWarp();
String destinationWarpBefore = teleporterComponent.getWarp();
CreateWarpWhenTeleporterPlacedSystem.createWarp(worldChunkComponent, blockStateInfo, data.warpName);
teleporterComponent.setOwnedWarp(data.warpName);
teleporterComponent.setIsCustomName(customName);
@@ -252,34 +245,20 @@ public class TeleporterSettingsPage extends InteractiveCustomUIPage<TeleporterSe
| (data.isBlockRelative ? 64 : 0)
)
);
teleporterComponent.setWarp(data.warp != null && !data.warp.isEmpty() ? data.warp : null);
teleporterComponent.setWarp(data.destinationWarp != null && !data.destinationWarp.isEmpty() ? data.destinationWarp : null);
break;
case WARP:
teleporterComponent.setWorldUuid(null);
teleporterComponent.setTransform(null);
teleporterComponent.setWarp(data.warp != null && !data.warp.isEmpty() ? data.warp : null);
teleporterComponent.setWarp(data.destinationWarp != null && !data.destinationWarp.isEmpty() ? data.destinationWarp : null);
}
String newState = "default";
if (teleporterComponent.isValid()) {
newState = this.activeState != null ? this.activeState : "default";
boolean ownChanged = !Objects.equals(ownedWarpBefore, teleporterComponent.getOwnedWarp());
boolean destinationChanged = !Objects.equals(destinationWarpBefore, teleporterComponent.getWarp());
if (ownChanged || destinationChanged) {
World world = store.getExternalData().getWorld();
TurnOffTeleportersSystem.updatePortalBlocksInWorld(world);
}
boolean isDifferentState = false;
BlockType blockType = worldChunkComponent.getBlockType(targetX, targetY, targetZ);
if (blockType != null) {
String currentState = blockType.getStateForBlock(blockType);
isDifferentState = !newState.equals(currentState);
}
if (isDifferentState) {
BlockType variantBlockType = blockType.getBlockForState(newState);
if (variantBlockType != null) {
worldChunkComponent.setBlockInteractionState(targetX, targetY, targetZ, variantBlockType, newState, true);
}
}
blockStateInfo.markNeedsSaving();
}
}
}
@@ -381,7 +360,9 @@ public class TeleporterSettingsPage extends InteractiveCustomUIPage<TeleporterSe
.add()
.append(new KeyedCodec<>("@World", Codec.STRING), (pageEventData, o) -> pageEventData.world = o, pageEventData -> pageEventData.world)
.add()
.append(new KeyedCodec<>("@Warp", Codec.STRING), (pageEventData, o) -> pageEventData.warp = o, pageEventData -> pageEventData.warp)
.append(
new KeyedCodec<>("@Warp", Codec.STRING), (pageEventData, o) -> pageEventData.destinationWarp = o, pageEventData -> pageEventData.destinationWarp
)
.add()
.append(new KeyedCodec<>("@NewWarp", Codec.STRING), (pageEventData, o) -> pageEventData.warpName = o, pageEventData -> pageEventData.warpName)
.add()
@@ -400,7 +381,7 @@ public class TeleporterSettingsPage extends InteractiveCustomUIPage<TeleporterSe
public boolean pitchIsRelative;
public boolean rollIsRelative;
public String world;
public String warp;
public String destinationWarp;
@Nullable
public String warpName;
}

View File

@@ -42,18 +42,9 @@ public class TeleporterSettingsPageSupplier implements OpenCustomUIInteraction.C
(supplier, parent) -> supplier.mode = parent.mode
)
.add()
.appendInherited(
new KeyedCodec<>("ActiveState", Codec.STRING),
(supplier, o) -> supplier.activeState = o,
supplier -> supplier.activeState,
(supplier, parent) -> supplier.activeState = parent.activeState
)
.add()
.build();
private boolean create = true;
private TeleporterSettingsPage.Mode mode = TeleporterSettingsPage.Mode.FULL;
@Nullable
private String activeState;
@Nullable
@Override
@@ -91,7 +82,7 @@ public class TeleporterSettingsPageSupplier implements OpenCustomUIInteraction.C
blockRef = chunkComponentStore.addEntity(holder, AddReason.SPAWN);
}
return blockRef != null && blockRef.isValid() ? new TeleporterSettingsPage(playerRef, blockRef, this.mode, this.activeState) : null;
return blockRef != null && blockRef.isValid() ? new TeleporterSettingsPage(playerRef, blockRef, this.mode) : null;
}
}
}

View File

@@ -0,0 +1,98 @@
package com.hypixel.hytale.builtin.adventure.teleporter.system;
import com.hypixel.hytale.builtin.adventure.teleporter.component.Teleporter;
import com.hypixel.hytale.builtin.teleport.TeleportPlugin;
import com.hypixel.hytale.builtin.teleport.Warp;
import com.hypixel.hytale.component.AddReason;
import com.hypixel.hytale.component.CommandBuffer;
import com.hypixel.hytale.component.ComponentAccessor;
import com.hypixel.hytale.component.Ref;
import com.hypixel.hytale.component.RemoveReason;
import com.hypixel.hytale.component.Store;
import com.hypixel.hytale.component.query.AndQuery;
import com.hypixel.hytale.component.query.Query;
import com.hypixel.hytale.component.system.RefSystem;
import com.hypixel.hytale.math.util.ChunkUtil;
import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockType;
import com.hypixel.hytale.server.core.modules.block.BlockModule;
import com.hypixel.hytale.server.core.universe.world.World;
import com.hypixel.hytale.server.core.universe.world.chunk.WorldChunk;
import com.hypixel.hytale.server.core.universe.world.storage.ChunkStore;
import javax.annotation.Nonnull;
import org.checkerframework.checker.nullness.compatqual.NullableDecl;
public class TurnOffTeleportersSystem extends RefSystem<ChunkStore> {
public static final Query<ChunkStore> QUERY = Query.and(Teleporter.getComponentType(), BlockModule.BlockStateInfo.getComponentType());
@Override
public void onEntityAdded(
@Nonnull Ref<ChunkStore> ref, @Nonnull AddReason reason, @Nonnull Store<ChunkStore> store, @Nonnull CommandBuffer<ChunkStore> commandBuffer
) {
if (reason == AddReason.LOAD) {
updatePortalBlocksInWorld(store.getExternalData().getWorld());
}
}
@Override
public void onEntityRemove(
@Nonnull Ref<ChunkStore> ref, @Nonnull RemoveReason reason, @Nonnull Store<ChunkStore> store, @Nonnull CommandBuffer<ChunkStore> commandBuffer
) {
if (reason == RemoveReason.REMOVE) {
updatePortalBlocksInWorld(store.getExternalData().getWorld());
}
}
public static void updatePortalBlocksInWorld(World world) {
Store<ChunkStore> store = world.getChunkStore().getStore();
AndQuery<ChunkStore> entityQuery = Query.and(Teleporter.getComponentType(), BlockModule.BlockStateInfo.getComponentType());
store.forEachChunk(entityQuery, (archetypeChunk, commandBuffer) -> {
for (int i = 0; i < archetypeChunk.size(); i++) {
Ref<ChunkStore> ref = archetypeChunk.getReferenceTo(i);
updatePortalBlockInWorld(ref, commandBuffer);
}
});
}
private static void updatePortalBlockInWorld(Ref<ChunkStore> ref, ComponentAccessor<ChunkStore> store) {
if (ref.isValid()) {
Teleporter teleporter = store.getComponent(ref, Teleporter.getComponentType());
BlockModule.BlockStateInfo blockState = store.getComponent(ref, BlockModule.BlockStateInfo.getComponentType());
updatePortalBlockInWorld(store, teleporter, blockState);
}
}
public static void updatePortalBlockInWorld(ComponentAccessor<ChunkStore> store, Teleporter teleporter, BlockModule.BlockStateInfo blockStateInfo) {
Ref<ChunkStore> chunkRef = blockStateInfo.getChunkRef();
if (chunkRef.isValid()) {
WorldChunk worldChunkComponent = store.getComponent(chunkRef, WorldChunk.getComponentType());
if (worldChunkComponent != null) {
int index = blockStateInfo.getIndex();
int x = ChunkUtil.xFromBlockInColumn(index);
int y = ChunkUtil.yFromBlockInColumn(index);
int z = ChunkUtil.zFromBlockInColumn(index);
BlockType blockType = worldChunkComponent.getBlockType(x, y, z);
if (blockType != null) {
String warpId = teleporter.getWarp();
Warp destinationWarp = warpId == null ? null : TeleportPlugin.get().getWarps().get(warpId);
String currentState = blockType.getStateForBlock(blockType);
String desiredState = destinationWarp == null ? "default" : "Active";
if (!desiredState.equals(currentState)) {
worldChunkComponent.setBlockInteractionState(x, y, z, blockType, desiredState, false);
blockStateInfo.markNeedsSaving(store);
}
if (destinationWarp == null) {
teleporter.setWarp(null);
blockStateInfo.markNeedsSaving(store);
}
}
}
}
}
@NullableDecl
@Override
public Query<ChunkStore> getQuery() {
return QUERY;
}
}

View File

@@ -101,7 +101,7 @@ public class AssetEditorPacketHandler extends GenericPacketHandler {
@Nonnull
@Override
public String getIdentifier() {
return "{Editor(" + NettyUtil.formatRemoteAddress(this.channel) + "), " + this.editorClient.getUuid() + ", " + this.editorClient.getUsername() + "}";
return "{Editor(" + NettyUtil.formatRemoteAddress(this.getChannel()) + "), " + this.editorClient.getUuid() + ", " + this.editorClient.getUsername() + "}";
}
@Override
@@ -137,6 +137,7 @@ public class AssetEditorPacketHandler extends GenericPacketHandler {
this.registerHandler(316, p -> this.handle((AssetEditorCreateAssetPack)p));
this.registerHandler(315, p -> this.handle((AssetEditorUpdateAssetPack)p));
this.registerHandler(317, p -> this.handle((AssetEditorDeleteAssetPack)p));
this.registerHandler(232, p -> this.handle((UpdateLanguage)p));
}
public void handle(@Nonnull AssetEditorSubscribeModifiedAssetsChanges packet) {
@@ -400,11 +401,11 @@ public class AssetEditorPacketHandler extends GenericPacketHandler {
"%s - %s at %s left with reason: %s - %s",
this.editorClient.getUuid(),
this.editorClient.getUsername(),
NettyUtil.formatRemoteAddress(this.channel),
NettyUtil.formatRemoteAddress(this.getChannel()),
packet.type.name(),
packet.reason
);
this.channel.close();
this.getChannel().close();
}
private boolean lacksPermission(int token) {

View File

@@ -38,7 +38,7 @@ import com.hypixel.hytale.component.ComponentAccessor;
import com.hypixel.hytale.component.Ref;
import com.hypixel.hytale.event.EventRegistry;
import com.hypixel.hytale.event.IEventDispatcher;
import com.hypixel.hytale.protocol.Packet;
import com.hypixel.hytale.protocol.ToClientPacket;
import com.hypixel.hytale.protocol.packets.asseteditor.AssetEditorAsset;
import com.hypixel.hytale.protocol.packets.asseteditor.AssetEditorAssetListUpdate;
import com.hypixel.hytale.protocol.packets.asseteditor.AssetEditorAssetPackSetup;
@@ -78,6 +78,7 @@ import com.hypixel.hytale.server.core.asset.AssetPackRegisterEvent;
import com.hypixel.hytale.server.core.asset.AssetPackUnregisterEvent;
import com.hypixel.hytale.server.core.asset.AssetRegistryLoader;
import com.hypixel.hytale.server.core.asset.common.events.CommonAssetMonitorEvent;
import com.hypixel.hytale.server.core.config.ModConfig;
import com.hypixel.hytale.server.core.io.PacketHandler;
import com.hypixel.hytale.server.core.io.ServerManager;
import com.hypixel.hytale.server.core.io.handlers.InitialPacketHandler;
@@ -806,8 +807,8 @@ public class AssetEditorPlugin extends JavaPlugin {
String newPackId = newPackIdentifier.toString();
Path packPath = dataSource.getRootPath();
HytaleServerConfig serverConfig = HytaleServer.get().getConfig();
HytaleServerConfig.ModConfig.setBoot(serverConfig, newPackIdentifier, true);
Map<PluginIdentifier, HytaleServerConfig.ModConfig> modConfig = serverConfig.getModConfig();
HytaleServerConfig.setBoot(serverConfig, newPackIdentifier, true);
Map<PluginIdentifier, ModConfig> modConfig = serverConfig.getModConfig();
modConfig.remove(PluginIdentifier.fromString(packId));
serverConfig.markChanged();
if (serverConfig.consumeHasChanged()) {
@@ -816,7 +817,7 @@ public class AssetEditorPlugin extends JavaPlugin {
AssetModule assetModule = AssetModule.get();
assetModule.unregisterPack(packId);
assetModule.registerPack(newPackId, packPath, manifest);
assetModule.registerPack(newPackId, packPath, manifest, false);
}
}
}
@@ -886,13 +887,13 @@ public class AssetEditorPlugin extends JavaPlugin {
Path manifestPath = packPath.resolve("manifest.json");
BsonUtil.writeSync(manifestPath, PluginManifest.CODEC, manifest, this.getLogger());
HytaleServerConfig serverConfig = HytaleServer.get().getConfig();
HytaleServerConfig.ModConfig.setBoot(serverConfig, new PluginIdentifier(manifest), true);
HytaleServerConfig.setBoot(serverConfig, new PluginIdentifier(manifest), true);
serverConfig.markChanged();
if (serverConfig.consumeHasChanged()) {
HytaleServerConfig.save(serverConfig).join();
}
AssetModule.get().registerPack(packId, packPath, manifest);
AssetModule.get().registerPack(packId, packPath, manifest, false);
editorClient.sendSuccessReply(requestToken, Messages.PACK_CREATED);
this.getLogger().at(Level.INFO).log("Created new pack: %s at %s", packId, packPath);
} catch (IOException var12) {
@@ -965,7 +966,7 @@ public class AssetEditorPlugin extends JavaPlugin {
editorClient.getPacketHandler().write(new AssetEditorExportAssetInitialize(new AssetEditorAsset(null, assetPath.toPacket()), null, 0, false));
} else {
byte[][] parts = ArrayUtil.split(bytes, 2621440);
Packet[] packets = new Packet[2 + parts.length];
ToClientPacket[] packets = new ToClientPacket[2 + parts.length];
packets[0] = new AssetEditorExportAssetInitialize(new AssetEditorAsset(null, assetPath.toPacket()), null, bytes.length, false);
for (int partIndex = 0; partIndex < parts.length; partIndex++) {
@@ -1421,12 +1422,13 @@ public class AssetEditorPlugin extends JavaPlugin {
editorClient.sendPopupNotification(AssetEditorPopupNotificationType.Error, Messages.REQUEST_CHILD_IDS_ASSET_TYPE_MISSING);
} else {
AssetStore assetStore = assetStoreTypeHandler.getAssetStore();
AssetMap assetMap = assetStore.getAssetMap();
Object key = assetStore.decodeFilePathKey(assetPath.path());
Set children = assetStore.getAssetMap().getChildren(key);
Set children = assetMap.getChildren(key);
HashSet childrenIds = new HashSet();
if (children != null) {
for (Object child : children) {
if (assetStore.getAssetMap().getPath(child) != null) {
if (assetMap.getPath(child) != null) {
childrenIds.add(child.toString());
}
}
@@ -1796,13 +1798,13 @@ public class AssetEditorPlugin extends JavaPlugin {
}
}
private void sendPacketToAllEditorUsers(@Nonnull Packet packet) {
private void sendPacketToAllEditorUsers(@Nonnull ToClientPacket packet) {
for (EditorClient editorClient : this.clientOpenAssetPathMapping.keySet()) {
editorClient.getPacketHandler().write(packet);
}
}
private void sendPacketToAllEditorUsersExcept(@Nonnull Packet packet, EditorClient ignoreEditorClient) {
private void sendPacketToAllEditorUsersExcept(@Nonnull ToClientPacket packet, EditorClient ignoreEditorClient) {
for (EditorClient editorClient : this.clientOpenAssetPathMapping.keySet()) {
if (!editorClient.equals(ignoreEditorClient)) {
editorClient.getPacketHandler().write(packet);

View File

@@ -86,7 +86,10 @@ public class StandardDataSource implements DataSource {
@Override
public void shutdown() {
this.saveSchedule.cancel(false);
if (this.saveSchedule != null) {
this.saveSchedule.cancel(false);
}
this.saveRecentModifications();
}

View File

@@ -129,6 +129,7 @@ import com.hypixel.hytale.codec.codecs.array.ArrayCodec;
import com.hypixel.hytale.codec.validation.Validators;
import com.hypixel.hytale.common.util.CompletableFutureUtil;
import com.hypixel.hytale.common.util.PathUtil;
import com.hypixel.hytale.component.AddReason;
import com.hypixel.hytale.component.Archetype;
import com.hypixel.hytale.component.CommandBuffer;
import com.hypixel.hytale.component.ComponentAccessor;
@@ -147,13 +148,11 @@ import com.hypixel.hytale.math.block.BlockCubeUtil;
import com.hypixel.hytale.math.block.BlockSphereUtil;
import com.hypixel.hytale.math.block.BlockUtil;
import com.hypixel.hytale.math.iterator.LineIterator;
import com.hypixel.hytale.math.matrix.Matrix4d;
import com.hypixel.hytale.math.util.ChunkUtil;
import com.hypixel.hytale.math.util.MathUtil;
import com.hypixel.hytale.math.vector.Vector3d;
import com.hypixel.hytale.math.vector.Vector3f;
import com.hypixel.hytale.math.vector.Vector3i;
import com.hypixel.hytale.math.vector.Vector4d;
import com.hypixel.hytale.math.vector.VectorBoxUtil;
import com.hypixel.hytale.metrics.MetricProvider;
import com.hypixel.hytale.metrics.MetricResults;
@@ -195,13 +194,17 @@ import com.hypixel.hytale.server.core.command.system.CommandManager;
import com.hypixel.hytale.server.core.command.system.CommandRegistry;
import com.hypixel.hytale.server.core.command.system.CommandSender;
import com.hypixel.hytale.server.core.entity.UUIDComponent;
import com.hypixel.hytale.server.core.entity.entities.BlockEntity;
import com.hypixel.hytale.server.core.entity.entities.Player;
import com.hypixel.hytale.server.core.event.events.player.PlayerConnectEvent;
import com.hypixel.hytale.server.core.event.events.player.PlayerDisconnectEvent;
import com.hypixel.hytale.server.core.inventory.ItemStack;
import com.hypixel.hytale.server.core.inventory.container.ItemContainer;
import com.hypixel.hytale.server.core.io.ServerManager;
import com.hypixel.hytale.server.core.modules.entity.component.HeadRotation;
import com.hypixel.hytale.server.core.modules.entity.component.TransformComponent;
import com.hypixel.hytale.server.core.modules.entity.tracker.EntityTrackerSystems;
import com.hypixel.hytale.server.core.modules.entity.tracker.NetworkId;
import com.hypixel.hytale.server.core.modules.interaction.interaction.config.Interaction;
import com.hypixel.hytale.server.core.modules.interaction.interaction.config.RootInteraction;
import com.hypixel.hytale.server.core.modules.interaction.interaction.config.server.OpenCustomUIInteraction;
@@ -223,7 +226,6 @@ import com.hypixel.hytale.server.core.prefab.selection.standard.FeedbackConsumer
import com.hypixel.hytale.server.core.universe.PlayerRef;
import com.hypixel.hytale.server.core.universe.world.SoundUtil;
import com.hypixel.hytale.server.core.universe.world.World;
import com.hypixel.hytale.server.core.universe.world.accessor.BlockAccessor;
import com.hypixel.hytale.server.core.universe.world.accessor.ChunkAccessor;
import com.hypixel.hytale.server.core.universe.world.accessor.LocalCachedChunkAccessor;
import com.hypixel.hytale.server.core.universe.world.accessor.OverridableChunkAccessor;
@@ -280,6 +282,7 @@ import java.util.function.Predicate;
import java.util.logging.Level;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.joml.Quaterniond;
public class BuilderToolsPlugin extends JavaPlugin implements SelectionProvider, MetricProvider {
public static final String EDITOR_BLOCK = "Editor_Block";
@@ -912,15 +915,47 @@ public class BuilderToolsPlugin extends JavaPlugin implements SelectionProvider,
@Nonnull
public BuilderToolsPlugin.ActionEntry restore(Ref<EntityStore> ref, Player player, World world, ComponentAccessor<EntityStore> componentAccessor) {
List<SelectionSnapshot<?>> collector = Collections.emptyList();
List<Ref<EntityStore>> recreatedEntityRefs = null;
if (this.action == BuilderToolsPlugin.Action.ROTATE) {
PrototypePlayerBuilderToolSettings protoSettings = ToolOperation.getOrCreatePrototypeSettings(player.getUuid());
List<Ref<EntityStore>> currentRefs = protoSettings.getLastTransformEntityRefs();
if (currentRefs != null) {
Store<EntityStore> entityStore = world.getEntityStore().getStore();
for (Ref<EntityStore> currentRef : currentRefs) {
if (currentRef.isValid()) {
collector = (List<SelectionSnapshot<?>>)(collector.isEmpty() ? new ObjectArrayList<>() : collector);
collector.add(new EntityRemoveSnapshot(currentRef));
entityStore.removeEntity(currentRef, RemoveReason.UNLOAD);
}
}
protoSettings.setLastTransformEntityRefs(null);
}
}
for (SelectionSnapshot<?> snapshot : this.snapshots) {
SelectionSnapshot<?> nextSnapshot = snapshot.restore(ref, player, world, componentAccessor);
if (nextSnapshot != null) {
collector = (List<SelectionSnapshot<?>>)(collector.isEmpty() ? new ObjectArrayList<>() : collector);
collector.add(nextSnapshot);
if (this.action != BuilderToolsPlugin.Action.ROTATE || !(snapshot instanceof EntityAddSnapshot)) {
SelectionSnapshot<?> nextSnapshot = snapshot.restore(ref, player, world, componentAccessor);
if (nextSnapshot != null) {
collector = (List<SelectionSnapshot<?>>)(collector.isEmpty() ? new ObjectArrayList<>() : collector);
collector.add(nextSnapshot);
if (nextSnapshot instanceof EntityAddSnapshot entityAddSnapshot) {
if (recreatedEntityRefs == null) {
recreatedEntityRefs = new ArrayList<>();
}
recreatedEntityRefs.add(entityAddSnapshot.getEntityRef());
}
}
}
}
if (this.action == BuilderToolsPlugin.Action.ROTATE && recreatedEntityRefs != null && !recreatedEntityRefs.isEmpty()) {
PrototypePlayerBuilderToolSettings prototypeSettings = ToolOperation.getOrCreatePrototypeSettings(player.getUuid());
prototypeSettings.setLastTransformEntityRefs(recreatedEntityRefs);
}
return new BuilderToolsPlugin.ActionEntry(this.action, collector);
}
}
@@ -1925,88 +1960,94 @@ public class BuilderToolsPlugin extends JavaPlugin implements SelectionProvider,
this.pushHistory(BuilderToolsPlugin.Action.EXTRUDE, new BlockSelectionSnapshot(before));
BlockSelection after = new BlockSelection(totalBlocks, 0);
after.copyPropertiesFrom(before);
this.extendFaceFindBlocks(
accessor, BlockType.getAssetMap(), before, after, x + normalX, y + normalY, z + normalZ, normalX, normalY, normalZ, extrudeDepth, blockId, min, max
);
Vector3i offset = new Vector3i(0, 0, 0);
for (int i = 0; i < extrudeDepth; i++) {
offset.x = normalX * i;
offset.y = normalY * i;
offset.z = normalZ * i;
after.placeNoReturn("Set", this.player, BuilderToolsPlugin.FEEDBACK_CONSUMER, world, offset, null, componentAccessor);
if (x >= min.getX() && x <= max.getX()) {
if (y >= min.getY() && y <= max.getY()) {
if (z >= min.getZ() && z <= max.getZ()) {
int testBlock = accessor.getBlock(x - normalX, y - normalY, z - normalZ);
BlockType testBlockType = BlockType.getAssetMap().getAsset(testBlock);
if (testBlockType != null && (testBlockType.getDrawType() == DrawType.Cube || testBlockType.getDrawType() == DrawType.CubeWithModel)) {
int xMod = Math.abs(normalX) == 1 ? 0 : 1;
int yMod = Math.abs(normalY) == 1 ? 0 : 1;
int zMod = Math.abs(normalZ) == 1 ? 0 : 1;
Vector3i surfaceMin = new Vector3i(x - radiusAllowed * xMod, y - radiusAllowed * yMod, z - radiusAllowed * zMod);
Vector3i surfaceMax = new Vector3i(x + radiusAllowed * xMod, y + radiusAllowed * yMod, z + radiusAllowed * zMod);
this.extendFaceFindBlocks(accessor, before, after, normalX, normalY, normalZ, extrudeDepth, blockId, min, max, surfaceMin, surfaceMax);
after.placeNoReturn("Set", this.player, BuilderToolsPlugin.FEEDBACK_CONSUMER, world, componentAccessor);
BuilderToolsPlugin.invalidateWorldMapForSelection(after, world);
long end = System.nanoTime();
long diff = end - start;
BuilderToolsPlugin.get()
.getLogger()
.at(Level.FINE)
.log("Took: %dns (%dms) to execute set of %d blocks", diff, TimeUnit.NANOSECONDS.toMillis(diff), after.getBlockCount());
this.sendUpdate();
this.sendArea();
}
}
}
}
BuilderToolsPlugin.invalidateWorldMapForSelection(after, world);
long end = System.nanoTime();
long diff = end - start;
BuilderToolsPlugin.get()
.getLogger()
.at(Level.FINE)
.log("Took: %dns (%dms) to execute set of %d blocks", diff, TimeUnit.NANOSECONDS.toMillis(diff), after.getBlockCount());
this.sendUpdate();
this.sendArea();
}
private void extendFaceFindBlocks(
@Nonnull ChunkAccessor accessor,
@Nonnull BlockTypeAssetMap<String, BlockType> assetMap,
@Nonnull LocalCachedChunkAccessor accessor,
@Nonnull BlockSelection before,
@Nonnull BlockSelection after,
int x,
int y,
int z,
int normalX,
int normalY,
int normalZ,
int extrudeDepth,
int blockId,
@Nonnull Vector3i min,
@Nonnull Vector3i max
@Nonnull Vector3i max,
@Nonnull Vector3i surfaceMin,
@Nonnull Vector3i surfaceMax
) {
if (x >= min.getX() && x <= max.getX()) {
if (y >= min.getY() && y <= max.getY()) {
if (z >= min.getZ() && z <= max.getZ()) {
int block = accessor.getBlock(x, y, z);
int testBlock = accessor.getBlock(x - normalX, y - normalY, z - normalZ);
BlockType testBlockType = assetMap.getAsset(testBlock);
if (testBlockType != null && (testBlockType.getDrawType() == DrawType.Cube || testBlockType.getDrawType() == DrawType.CubeWithModel)) {
if (!before.hasBlockAtWorldPos(x, y, z)) {
BlockAccessor blocks = accessor.getChunkIfInMemory(ChunkUtil.indexChunkFromBlock(x, z));
if (blocks != null) {
before.addBlockAtWorldPos(
x,
y,
z,
block,
blocks.getRotationIndex(x, y, z),
blocks.getFiller(x, y, z),
blocks.getSupportValue(x, y, z),
blocks.getBlockComponentHolder(x, y, z)
);
after.addBlockAtWorldPos(x, y, z, blockId, 0, 0, 0);
int xMin = surfaceMin.getX();
int yMin = surfaceMin.getY();
int zMin = surfaceMin.getZ();
int xMax = surfaceMax.getX();
int yMax = surfaceMax.getY();
int zMax = surfaceMax.getZ();
for (Vector3i side : Vector3i.BLOCK_SIDES) {
if ((normalX == 0 || side.getX() == 0) && (normalY == 0 || side.getY() == 0) && (normalZ == 0 || side.getZ() == 0)) {
this.extendFaceFindBlocks(
accessor,
assetMap,
before,
after,
x + side.getX(),
y + side.getY(),
z + side.getZ(),
normalX,
normalY,
normalZ,
extrudeDepth,
blockId,
min,
max
);
}
}
}
for (int x = xMin; x <= xMax; x++) {
for (int z = zMin; z <= zMax; z++) {
WorldChunk chunk = accessor.getChunk(ChunkUtil.indexChunkFromBlock(x, z));
for (int y = yMax; y >= yMin; y--) {
int currentBlock = chunk.getBlock(x, y, z);
int currentFluid = chunk.getFluidId(x, y, z);
if (currentBlock > 0) {
int xRes = x + normalX;
int yRes = y + normalY;
int zRes = z + normalZ;
currentBlock = chunk.getBlock(xRes, yRes, zRes);
before.addBlockAtWorldPos(
xRes,
yRes,
zRes,
currentBlock,
chunk.getRotationIndex(xRes, yRes, zRes),
chunk.getFiller(xRes, yRes, zRes),
chunk.getSupportValue(xRes, yRes, zRes),
chunk.getBlockComponentHolder(xRes, yRes, zRes)
);
after.addBlockAtWorldPos(xRes, yRes, zRes, blockId, 0, 0, 0);
for (int i = 0; i < extrudeDepth; i++) {
int extrudedBlockX = xRes + normalX * i;
int extrudedBlockY = yRes + normalY * i;
int extrudedBlockZ = zRes + normalZ * i;
before.addBlockAtWorldPos(
extrudedBlockX,
extrudedBlockY,
extrudedBlockZ,
currentBlock,
chunk.getRotationIndex(extrudedBlockX, extrudedBlockY, extrudedBlockZ),
chunk.getFiller(extrudedBlockX, extrudedBlockY, extrudedBlockZ),
chunk.getSupportValue(extrudedBlockX, extrudedBlockY, extrudedBlockZ),
chunk.getBlockComponentHolder(extrudedBlockX, extrudedBlockY, extrudedBlockZ)
);
after.addBlockAtWorldPos(extrudedBlockX, extrudedBlockY, extrudedBlockZ, blockId, 0, 0, 0);
}
}
}
@@ -2165,7 +2206,7 @@ public class BuilderToolsPlugin extends JavaPlugin implements SelectionProvider,
int settings,
@Nonnull ComponentAccessor<EntityStore> componentAccessor
) throws PrefabCopyException {
return this.copyOrCut(ref, xMin, yMin, zMin, xMax, yMax, zMax, settings, null, componentAccessor);
return this.copyOrCut(ref, xMin, yMin, zMin, xMax, yMax, zMax, settings, null, null, componentAccessor);
}
public int copyOrCut(
@@ -2179,6 +2220,22 @@ public class BuilderToolsPlugin extends JavaPlugin implements SelectionProvider,
int settings,
@Nullable Vector3i playerAnchor,
@Nonnull ComponentAccessor<EntityStore> componentAccessor
) throws PrefabCopyException {
return this.copyOrCut(ref, xMin, yMin, zMin, xMax, yMax, zMax, settings, playerAnchor, null, componentAccessor);
}
public int copyOrCut(
@Nonnull Ref<EntityStore> ref,
int xMin,
int yMin,
int zMin,
int xMax,
int yMax,
int zMax,
int settings,
@Nullable Vector3i playerAnchor,
@Nullable Set<Ref<EntityStore>> skipEntityRemoveSnapshotFor,
@Nonnull ComponentAccessor<EntityStore> componentAccessor
) throws PrefabCopyException {
World world = componentAccessor.getExternalData().getWorld();
long start = System.nanoTime();
@@ -2316,8 +2373,11 @@ public class BuilderToolsPlugin extends JavaPlugin implements SelectionProvider,
Holder<EntityStore> holder = store.copyEntity(e);
this.selection.addEntityFromWorld(holder);
if (cut) {
snapshots.add(new EntityRemoveSnapshot(e));
entitiesToRemove.add(e);
boolean shouldSkip = skipEntityRemoveSnapshotFor != null && skipEntityRemoveSnapshotFor.contains(e);
if (!shouldSkip) {
snapshots.add(new EntityRemoveSnapshot(e));
entitiesToRemove.add(e);
}
}
});
if (cut && entitiesToRemove != null) {
@@ -2433,36 +2493,48 @@ public class BuilderToolsPlugin extends JavaPlugin implements SelectionProvider,
return size;
}
public static RotationTuple transformRotation(RotationTuple prevRot, Matrix4d transformationMatrix) {
public static RotationTuple transformRotation(RotationTuple prevRot, Quaterniond rotation) {
Vector3f forwardVec = new Vector3f(1.0F, 0.0F, 0.0F);
Vector3f upVec = new Vector3f(0.0F, 1.0F, 0.0F);
forwardVec = Rotation.rotate(forwardVec, prevRot.yaw(), prevRot.pitch(), prevRot.roll());
upVec = Rotation.rotate(upVec, prevRot.yaw(), prevRot.pitch(), prevRot.roll());
Vector3f newForward = transformationMatrix.multiplyDirection(forwardVec.toVector3d()).toVector3f();
Vector3f newUp = transformationMatrix.multiplyDirection(upVec.toVector3d()).toVector3f();
org.joml.Vector3d fwd = rotation.transform(new org.joml.Vector3d(forwardVec.x, forwardVec.y, forwardVec.z));
org.joml.Vector3d up = rotation.transform(new org.joml.Vector3d(upVec.x, upVec.y, upVec.z));
Vector3f newForward = new Vector3f((float)fwd.x, (float)fwd.y, (float)fwd.z);
Vector3f newUp = new Vector3f((float)up.x, (float)up.y, (float)up.z);
float bestScore = Float.MIN_VALUE;
RotationTuple bestRot = prevRot;
for (RotationTuple rotation : RotationTuple.VALUES) {
Vector3f rotForward = Rotation.rotate(new Vector3f(1.0F, 0.0F, 0.0F), rotation.yaw(), rotation.pitch(), rotation.roll());
Vector3f rotUp = Rotation.rotate(new Vector3f(0.0F, 1.0F, 0.0F), rotation.yaw(), rotation.pitch(), rotation.roll());
for (RotationTuple rot : RotationTuple.VALUES) {
Vector3f rotForward = Rotation.rotate(new Vector3f(1.0F, 0.0F, 0.0F), rot.yaw(), rot.pitch(), rot.roll());
Vector3f rotUp = Rotation.rotate(new Vector3f(0.0F, 1.0F, 0.0F), rot.yaw(), rot.pitch(), rot.roll());
float score = rotForward.dot(newForward) + rotUp.dot(newUp);
if (score > bestScore) {
bestScore = score;
bestRot = rotation;
bestRot = rot;
}
}
return bestRot;
}
private void transformEntityRotation(Vector3f rotation, Quaterniond deltaQuat) {
Quaterniond originalQuat = new Quaterniond().rotationYXZ(rotation.y, rotation.x, rotation.z);
Quaterniond resultQuat = deltaQuat.mul(originalQuat, new Quaterniond());
org.joml.Vector3d eulerAngles = resultQuat.getEulerAnglesYXZ(new org.joml.Vector3d());
rotation.assign((float)eulerAngles.x, (float)eulerAngles.y, (float)eulerAngles.z);
}
public void transformThenPasteClipboard(
@Nonnull BlockChange[] blockChanges,
@Nullable PrototypePlayerBuilderToolSettings.FluidChange[] fluidChanges,
@Nonnull Matrix4d transformationMatrix,
@Nullable PrototypePlayerBuilderToolSettings.EntityChange[] entityChanges,
@Nonnull Quaterniond rotation,
@Nonnull Vector3i translationOffset,
@Nonnull Vector3f rotationOrigin,
@Nonnull Vector3i initialPastePoint,
boolean keepEmptyBlocks,
@Nonnull PrototypePlayerBuilderToolSettings prototypeSettings,
ComponentAccessor<EntityStore> componentAccessor
) {
World world = componentAccessor.getExternalData().getWorld();
@@ -2477,35 +2549,33 @@ public class BuilderToolsPlugin extends JavaPlugin implements SelectionProvider,
}
}
Vector4d translationEndResult = new Vector4d(0.0, 0.0, 0.0, 1.0);
transformationMatrix.multiply(translationEndResult);
translationEndResult.x = translationEndResult.x + rotationOrigin.x;
translationEndResult.y = translationEndResult.y + rotationOrigin.y;
translationEndResult.z = translationEndResult.z + rotationOrigin.z;
int centerX = translationOffset.x + (int)rotationOrigin.x;
int centerY = translationOffset.y + (int)rotationOrigin.y;
int centerZ = translationOffset.z + (int)rotationOrigin.z;
BlockSelection before = new BlockSelection();
before.setPosition((int)translationEndResult.x, (int)translationEndResult.y, (int)translationEndResult.z);
before.setPosition(centerX, centerY, centerZ);
BlockSelection after = new BlockSelection(before);
LocalCachedChunkAccessor accessor = LocalCachedChunkAccessor.atWorldCoords(world, (int)translationEndResult.x, (int)translationEndResult.z, 50);
LocalCachedChunkAccessor accessor = LocalCachedChunkAccessor.atWorldCoords(world, centerX, centerZ, 50);
int minX = Integer.MAX_VALUE;
int minY = Integer.MAX_VALUE;
int minZ = Integer.MAX_VALUE;
int maxX = Integer.MIN_VALUE;
int maxY = Integer.MIN_VALUE;
int maxZ = Integer.MIN_VALUE;
Vector4d mutable4d = new Vector4d(0.0, 0.0, 0.0, 1.0);
org.joml.Vector3d mutableVec = new org.joml.Vector3d();
for (BlockChange blockChangex : blockChanges) {
mutable4d.assign(
mutableVec.set(
blockChangex.x - rotationOrigin.x + initialPastePoint.x + 0.5,
blockChangex.y - rotationOrigin.y + initialPastePoint.y + 0.5 + yOffsetOutOfGround,
blockChangex.z - rotationOrigin.z + initialPastePoint.z + 0.5,
1.0
blockChangex.z - rotationOrigin.z + initialPastePoint.z + 0.5
);
transformationMatrix.multiply(mutable4d);
rotation.transform(mutableVec);
mutableVec.add(translationOffset.x, translationOffset.y, translationOffset.z);
Vector3i rotatedLocation = new Vector3i(
(int)Math.floor(mutable4d.x + 0.1 + rotationOrigin.x - 0.5),
(int)Math.floor(mutable4d.y + 0.1 + rotationOrigin.y - 0.5),
(int)Math.floor(mutable4d.z + 0.1 + rotationOrigin.z - 0.5)
(int)Math.floor(mutableVec.x + 0.1 + rotationOrigin.x - 0.5),
(int)Math.floor(mutableVec.y + 0.1 + rotationOrigin.y - 0.5),
(int)Math.floor(mutableVec.z + 0.1 + rotationOrigin.z - 0.5)
);
minX = Math.min(minX, rotatedLocation.x);
minY = Math.min(minY, rotatedLocation.y);
@@ -2517,12 +2587,12 @@ public class BuilderToolsPlugin extends JavaPlugin implements SelectionProvider,
Holder<ChunkStore> holder = currentChunk.getBlockComponentHolder(rotatedLocation.x, rotatedLocation.y, rotatedLocation.z);
int blockIdInRotatedLocation = currentChunk.getBlock(rotatedLocation.x, rotatedLocation.y, rotatedLocation.z);
int filler = currentChunk.getFiller(rotatedLocation.x, rotatedLocation.y, rotatedLocation.z);
int rotation = currentChunk.getRotationIndex(rotatedLocation.x, rotatedLocation.y, rotatedLocation.z);
before.addBlockAtWorldPos(rotatedLocation.x, rotatedLocation.y, rotatedLocation.z, blockIdInRotatedLocation, rotation, filler, 0, holder);
int blockRotation = currentChunk.getRotationIndex(rotatedLocation.x, rotatedLocation.y, rotatedLocation.z);
before.addBlockAtWorldPos(rotatedLocation.x, rotatedLocation.y, rotatedLocation.z, blockIdInRotatedLocation, blockRotation, filler, 0, holder);
int originalFluidId = currentChunk.getFluidId(rotatedLocation.x, rotatedLocation.y, rotatedLocation.z);
byte originalFluidLevel = currentChunk.getFluidLevel(rotatedLocation.x, rotatedLocation.y, rotatedLocation.z);
before.addFluidAtWorldPos(rotatedLocation.x, rotatedLocation.y, rotatedLocation.z, originalFluidId, originalFluidLevel);
int newRotation = transformRotation(RotationTuple.get(blockChangex.rotation), transformationMatrix).index();
int newRotation = transformRotation(RotationTuple.get(blockChangex.rotation), rotation).index();
int blockIdToPlace = blockChangex.block;
if (blockChangex.block == 0 && keepEmptyBlocks) {
blockIdToPlace = editorBlockPrefabAir;
@@ -2557,27 +2627,92 @@ public class BuilderToolsPlugin extends JavaPlugin implements SelectionProvider,
int finalYOffsetOutOfGround = yOffsetOutOfGround;
if (fluidChanges != null) {
for (PrototypePlayerBuilderToolSettings.FluidChange fluidChange : fluidChanges) {
mutable4d.assign(
mutableVec.set(
fluidChange.x() - rotationOrigin.x + initialPastePoint.x + 0.5,
fluidChange.y() - rotationOrigin.y + initialPastePoint.y + 0.5 + finalYOffsetOutOfGround,
fluidChange.z() - rotationOrigin.z + initialPastePoint.z + 0.5,
1.0
fluidChange.z() - rotationOrigin.z + initialPastePoint.z + 0.5
);
transformationMatrix.multiply(mutable4d);
rotation.transform(mutableVec);
mutableVec.add(translationOffset.x, translationOffset.y, translationOffset.z);
Vector3i rotatedLocationx = new Vector3i(
(int)Math.floor(mutable4d.x + 0.1 + rotationOrigin.x - 0.5),
(int)Math.floor(mutable4d.y + 0.1 + rotationOrigin.y - 0.5),
(int)Math.floor(mutable4d.z + 0.1 + rotationOrigin.z - 0.5)
(int)Math.floor(mutableVec.x + 0.1 + rotationOrigin.x - 0.5),
(int)Math.floor(mutableVec.y + 0.1 + rotationOrigin.y - 0.5),
(int)Math.floor(mutableVec.z + 0.1 + rotationOrigin.z - 0.5)
);
after.addFluidAtWorldPos(rotatedLocationx.x, rotatedLocationx.y, rotatedLocationx.z, fluidChange.fluidId(), fluidChange.fluidLevel());
}
}
List<Ref<EntityStore>> previousEntityRefs = prototypeSettings.getLastTransformEntityRefs();
List<EntityRemoveSnapshot> previousEntitySnapshots = new ArrayList<>();
if (previousEntityRefs != null) {
Store<EntityStore> entityStore = world.getEntityStore().getStore();
for (Ref<EntityStore> ref : previousEntityRefs) {
if (ref.isValid()) {
previousEntitySnapshots.add(new EntityRemoveSnapshot(ref));
entityStore.removeEntity(ref, RemoveReason.UNLOAD);
}
}
}
List<Ref<EntityStore>> addedEntityRefs = new ArrayList<>();
if (entityChanges != null && entityChanges.length > 0) {
org.joml.Vector3d mutableEntityPos = new org.joml.Vector3d();
for (PrototypePlayerBuilderToolSettings.EntityChange entityChange : entityChanges) {
boolean isBlockEntity = entityChange.entityHolder().getComponent(BlockEntity.getComponentType()) != null;
double blockCenterOffset = isBlockEntity ? 0.5 : 0.0;
mutableEntityPos.set(
entityChange.x() - rotationOrigin.x,
entityChange.y() + blockCenterOffset - rotationOrigin.y + finalYOffsetOutOfGround,
entityChange.z() - rotationOrigin.z
);
rotation.transform(mutableEntityPos);
mutableEntityPos.add(translationOffset.x, translationOffset.y, translationOffset.z);
double newX = mutableEntityPos.x + rotationOrigin.x;
double newY = mutableEntityPos.y + rotationOrigin.y - blockCenterOffset;
double newZ = mutableEntityPos.z + rotationOrigin.z;
Holder<EntityStore> clonedHolder = entityChange.entityHolder().clone();
TransformComponent transformComponent = clonedHolder.getComponent(TransformComponent.getComponentType());
if (transformComponent != null && transformComponent.getPosition() != null) {
transformComponent.getPosition().assign(newX, newY, newZ);
Vector3f entityRotation = transformComponent.getRotation();
if (entityRotation != null) {
this.transformEntityRotation(entityRotation, rotation);
}
}
HeadRotation headRotation = clonedHolder.getComponent(HeadRotation.getComponentType());
if (headRotation != null && headRotation.getRotation() != null) {
this.transformEntityRotation(headRotation.getRotation(), rotation);
}
clonedHolder.putComponent(UUIDComponent.getComponentType(), new UUIDComponent(UUID.randomUUID()));
clonedHolder.removeComponent(EntityTrackerSystems.Visible.getComponentType());
clonedHolder.removeComponent(NetworkId.getComponentType());
Ref<EntityStore> entityRef = componentAccessor.addEntity(clonedHolder, AddReason.LOAD);
addedEntityRefs.add(entityRef);
}
}
if (minX != Integer.MAX_VALUE) {
before.setSelectionArea(new Vector3i(minX, minY, minZ), new Vector3i(maxX, maxY, maxZ));
}
this.pushHistory(BuilderToolsPlugin.Action.ROTATE, new BlockSelectionSnapshot(before));
prototypeSettings.setLastTransformEntityRefs(new ArrayList<>(addedEntityRefs));
List<SelectionSnapshot<?>> snapshots = new ObjectArrayList<>(addedEntityRefs.size() + previousEntitySnapshots.size() + 1);
for (Ref<EntityStore> entityRef : addedEntityRefs) {
snapshots.add(new EntityAddSnapshot(entityRef));
}
for (EntityRemoveSnapshot snapshot : previousEntitySnapshots) {
snapshots.add(snapshot);
}
snapshots.add(new BlockSelectionSnapshot(before));
this.pushHistory(BuilderToolsPlugin.Action.ROTATE, snapshots);
after.placeNoReturn("Transform 1/1", this.player, BuilderToolsPlugin.FEEDBACK_CONSUMER, world, componentAccessor);
BuilderToolsPlugin.invalidateWorldMapForSelection(after, world);
long end = System.nanoTime();
@@ -2590,24 +2725,27 @@ public class BuilderToolsPlugin extends JavaPlugin implements SelectionProvider,
this.sendArea();
}
public void transformSelectionPoints(@Nonnull Matrix4d transformationMatrix, @Nonnull Vector3f rotationOrigin) {
Vector3i newMin = this.transformBlockLocation(this.selection.getSelectionMin(), transformationMatrix, rotationOrigin);
Vector3i newMax = this.transformBlockLocation(this.selection.getSelectionMax(), transformationMatrix, rotationOrigin);
public void transformSelectionPoints(@Nonnull Quaterniond rotation, @Nonnull Vector3i translationOffset, @Nonnull Vector3f rotationOrigin) {
Vector3i newMin = this.transformBlockLocation(this.selection.getSelectionMin(), rotation, translationOffset, rotationOrigin);
Vector3i newMax = this.transformBlockLocation(this.selection.getSelectionMax(), rotation, translationOffset, rotationOrigin);
this.selection.setSelectionArea(Vector3i.min(newMin, newMax), Vector3i.max(newMin, newMax));
this.sendUpdate();
this.sendArea();
}
@Nonnull
public Vector3i transformBlockLocation(@Nonnull Vector3i blockLocation, @Nonnull Matrix4d transformationMatrix, @Nonnull Vector3f rotationOrigin) {
Vector4d relativeOffset = new Vector4d(
blockLocation.x - rotationOrigin.x + 0.5, blockLocation.y - rotationOrigin.y + 0.5, blockLocation.z - rotationOrigin.z + 0.5, 1.0
public Vector3i transformBlockLocation(
@Nonnull Vector3i blockLocation, @Nonnull Quaterniond rotation, @Nonnull Vector3i translationOffset, @Nonnull Vector3f rotationOrigin
) {
org.joml.Vector3d relative = new org.joml.Vector3d(
blockLocation.x - rotationOrigin.x + 0.5, blockLocation.y - rotationOrigin.y + 0.5, blockLocation.z - rotationOrigin.z + 0.5
);
transformationMatrix.multiply(relativeOffset);
rotation.transform(relative);
relative.add(translationOffset.x, translationOffset.y, translationOffset.z);
return new Vector3i(
(int)Math.floor(relativeOffset.x + rotationOrigin.x - 0.5 + 0.1),
(int)Math.floor(relativeOffset.y + rotationOrigin.y - 0.5 + 0.1),
(int)Math.floor(relativeOffset.z + rotationOrigin.z - 0.5 + 0.1)
(int)Math.floor(relative.x + rotationOrigin.x - 0.5 + 0.1),
(int)Math.floor(relative.y + rotationOrigin.y - 0.5 + 0.1),
(int)Math.floor(relative.z + rotationOrigin.z - 0.5 + 0.1)
);
}

View File

@@ -4,6 +4,7 @@ import com.hypixel.hytale.builtin.buildertools.scriptedbrushes.BrushConfig;
import com.hypixel.hytale.builtin.buildertools.scriptedbrushes.BrushConfigCommandExecutor;
import com.hypixel.hytale.builtin.buildertools.tooloperations.ToolOperation;
import com.hypixel.hytale.component.ComponentAccessor;
import com.hypixel.hytale.component.Holder;
import com.hypixel.hytale.component.Ref;
import com.hypixel.hytale.math.block.BlockUtil;
import com.hypixel.hytale.math.vector.Vector3i;
@@ -14,6 +15,7 @@ import com.hypixel.hytale.server.core.entity.entities.Player;
import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.UUID;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@@ -38,9 +40,13 @@ public class PrototypePlayerBuilderToolSettings {
@Nullable
private PrototypePlayerBuilderToolSettings.FluidChange[] fluidChangesForPlaySelectionToolPasteMode = null;
@Nullable
private PrototypePlayerBuilderToolSettings.EntityChange[] entityChangesForPlaySelectionToolPasteMode = null;
@Nullable
private Vector3i lastBrushPosition = null;
@Nullable
private Vector3i blockChangeOffsetOrigin = null;
@Nullable
private List<Ref<EntityStore>> lastTransformEntityRefs = null;
public PrototypePlayerBuilderToolSettings(UUID player) {
this.player = player;
@@ -60,6 +66,7 @@ public class PrototypePlayerBuilderToolSettings {
if (!this.isInSelectionTransformationMode) {
this.blockChangesForPlaySelectionToolPasteMode = null;
this.fluidChangesForPlaySelectionToolPasteMode = null;
this.entityChangesForPlaySelectionToolPasteMode = null;
this.blockChangeOffsetOrigin = null;
}
}
@@ -98,6 +105,15 @@ public class PrototypePlayerBuilderToolSettings {
return this.fluidChangesForPlaySelectionToolPasteMode;
}
public void setEntityChangesForPlaySelectionToolPasteMode(@Nullable PrototypePlayerBuilderToolSettings.EntityChange[] entityChanges) {
this.entityChangesForPlaySelectionToolPasteMode = entityChanges;
}
@Nullable
public PrototypePlayerBuilderToolSettings.EntityChange[] getEntityChangesForPlaySelectionToolPasteMode() {
return this.entityChangesForPlaySelectionToolPasteMode;
}
public void setBlockChangeOffsetOrigin(@Nullable Vector3i blockChangeOffsetOrigin) {
this.blockChangeOffsetOrigin = blockChangeOffsetOrigin;
}
@@ -107,6 +123,19 @@ public class PrototypePlayerBuilderToolSettings {
return this.blockChangeOffsetOrigin;
}
public void setLastTransformEntityRefs(@Nullable List<Ref<EntityStore>> refs) {
this.lastTransformEntityRefs = refs;
}
@Nullable
public List<Ref<EntityStore>> getLastTransformEntityRefs() {
return this.lastTransformEntityRefs;
}
public void clearLastTransformEntityRefs() {
this.lastTransformEntityRefs = null;
}
@Nonnull
public LongOpenHashSet addIgnoredPaintOperation() {
LongOpenHashSet longs = new LongOpenHashSet();
@@ -202,6 +231,9 @@ public class PrototypePlayerBuilderToolSettings {
}
}
public record EntityChange(double x, double y, double z, Holder<EntityStore> entityHolder) {
}
public record FluidChange(int x, int y, int z, int fluidId, byte fluidLevel) {
}
}

View File

@@ -25,7 +25,9 @@ public class ContractSelectionCommand extends AbstractPlayerCommand {
@Nonnull
private final RequiredArg<Integer> distanceArg = this.withRequiredArg("distance", "server.commands.contract.arg.distance.desc", ArgTypes.INTEGER);
@Nonnull
private final OptionalArg<List<Axis>> axisArg = this.withListOptionalArg("axis", "command.contract.arg.axis.desc", ArgTypes.forEnum("Axis", Axis.class));
private final OptionalArg<List<Axis>> axisArg = this.withListOptionalArg(
"axis", "server.commands.contract.arg.axis.desc", ArgTypes.forEnum("Axis", Axis.class)
);
public ContractSelectionCommand() {
super("contractSelection", "server.commands.contract.desc");

View File

@@ -89,7 +89,7 @@ public class BrushConfig {
this.executionErrorMessage = null;
this.originOffset = new Vector3i(0, 0, 0);
this.originAfterOffset = null;
this.shape = BrushShape.Cube;
this.shape = BrushShape.Sphere;
this.shapeWidth = 5;
this.shapeHeight = 5;
this.shapeThickness = 0;

View File

@@ -20,7 +20,7 @@ public class ShapeOperation extends SequenceBrushOperation {
.documentation("Changes the shape of the brush editing area")
.build();
@Nonnull
public BrushShape brushShapeArg = BrushShape.Cube;
public BrushShape brushShapeArg = BrushShape.Sphere;
public ShapeOperation() {
super("Shape", "Changes the shape of the brush editing area", false);

View File

@@ -4,6 +4,8 @@ import com.hypixel.hytale.builtin.creativehub.command.HubCommand;
import com.hypixel.hytale.builtin.creativehub.config.CreativeHubEntityConfig;
import com.hypixel.hytale.builtin.creativehub.config.CreativeHubWorldConfig;
import com.hypixel.hytale.builtin.creativehub.interactions.HubPortalInteraction;
import com.hypixel.hytale.builtin.creativehub.systems.ReturnToHubButtonSystem;
import com.hypixel.hytale.builtin.creativehub.ui.ReturnToHubButtonUI;
import com.hypixel.hytale.builtin.instances.InstancesPlugin;
import com.hypixel.hytale.builtin.instances.config.InstanceEntityConfig;
import com.hypixel.hytale.builtin.instances.config.InstanceWorldConfig;
@@ -100,7 +102,10 @@ public class CreativeHubPlugin extends JavaPlugin {
config -> {
config.setUuid(UUID.randomUUID());
config.setDeleteOnRemove(false);
config.setDisplayName(WorldConfig.formatDisplayName(instanceAssetName));
if (config.getDisplayName() == null) {
config.setDisplayName(WorldConfig.formatDisplayName(instanceAssetName));
}
config.getPluginConfig().remove(InstanceWorldConfig.class);
config.markChanged();
long start = System.nanoTime();
@@ -148,9 +153,11 @@ public class CreativeHubPlugin extends JavaPlugin {
this.getCodecRegistry(WorldConfig.PLUGIN_CODEC).register(CreativeHubWorldConfig.class, "CreativeHub", CreativeHubWorldConfig.CODEC);
this.creativeHubEntityConfigComponentType = this.getEntityStoreRegistry()
.registerComponent(CreativeHubEntityConfig.class, "CreativeHub", CreativeHubEntityConfig.CODEC);
this.getEntityStoreRegistry().registerSystem(new ReturnToHubButtonSystem());
this.getEventRegistry().registerGlobal(PlayerConnectEvent.class, CreativeHubPlugin::onPlayerConnect);
this.getEventRegistry().registerGlobal(RemoveWorldEvent.class, CreativeHubPlugin::onWorldRemove);
this.getEventRegistry().registerGlobal(AddPlayerToWorldEvent.class, CreativeHubPlugin::onPlayerAddToWorld);
ReturnToHubButtonUI.register();
}
private static void onWorldRemove(@Nonnull RemoveWorldEvent event) {
@@ -212,9 +219,11 @@ public class CreativeHubPlugin extends JavaPlugin {
World parentWorld = Universe.get().getWorld(hubEntityConfig.getParentHubWorldUuid());
if (parentWorld != null) {
World hubInstance = get().getActiveHubInstance(parentWorld);
if (!world.equals(hubInstance)) {
PlayerRef playerRef = holder.getComponent(PlayerRef.getComponentType());
if (playerRef != null) {
boolean isInHubInstance = world.equals(hubInstance);
PlayerRef playerRef = holder.getComponent(PlayerRef.getComponentType());
if (playerRef != null) {
ReturnToHubButtonUI.send(playerRef, isInHubInstance);
if (!isInHubInstance) {
world.execute(() -> playerRef.sendMessage(MESSAGE_HUB_RETURN_HINT));
}
}

View File

@@ -27,7 +27,7 @@ public class HubCommand extends AbstractPlayerCommand {
public HubCommand() {
super("hub", "server.commands.hub.desc");
this.addAliases("converge", "convergence");
this.addAliases("cosmos", "crossroads");
this.setPermissionGroup(GameMode.Creative);
}

View File

@@ -159,47 +159,49 @@ public class HubPortalInteraction extends SimpleInstantInteraction {
} else {
UUID playerUUID = uuidComponent.getUuid();
CreativeHubEntityConfig hubEntityConfig = componentAccessor.getComponent(playerRef, CreativeHubEntityConfig.getComponentType());
originalWorld.execute(playerRefComponent::removeFromStore);
worldFuture.orTimeout(1L, TimeUnit.MINUTES).thenCompose(world -> {
PlayerWorldData worldData = perWorldData.get(world.getName());
if (worldData != null && worldData.getLastPosition() != null) {
return world.addPlayer(playerRefComponent, worldData.getLastPosition(), Boolean.TRUE, Boolean.FALSE);
} else {
ISpawnProvider spawnProvider = world.getWorldConfig().getSpawnProvider();
Transform spawnPoint = spawnProvider != null ? spawnProvider.getSpawnPoint(world, playerUUID) : null;
return world.addPlayer(playerRefComponent, spawnPoint, Boolean.TRUE, Boolean.FALSE);
}
}).whenComplete((ret, ex) -> {
if (ex != null) {
LOGGER.at(Level.SEVERE).withCause(ex).log("Failed to teleport %s to permanent world", playerRefComponent.getUsername());
}
if (ret == null) {
if (originalWorld.isAlive()) {
originalWorld.addPlayer(playerRefComponent, originalPosition, Boolean.TRUE, Boolean.FALSE);
CompletableFuture.runAsync(playerRefComponent::removeFromStore, originalWorld)
.thenCombine(worldFuture.orTimeout(1L, TimeUnit.MINUTES), (v, world) -> (World)world)
.thenCompose(world -> {
PlayerWorldData worldData = perWorldData.get(world.getName());
if (worldData != null && worldData.getLastPosition() != null) {
return world.addPlayer(playerRefComponent, worldData.getLastPosition(), Boolean.TRUE, Boolean.FALSE);
} else {
if (hubEntityConfig != null && hubEntityConfig.getParentHubWorldUuid() != null) {
World parentWorld = Universe.get().getWorld(hubEntityConfig.getParentHubWorldUuid());
if (parentWorld != null) {
CreativeHubWorldConfig parentHubConfig = CreativeHubWorldConfig.get(parentWorld.getWorldConfig());
if (parentHubConfig != null && parentHubConfig.getStartupInstance() != null) {
World hubInstance = CreativeHubPlugin.get().getOrSpawnHubInstance(parentWorld, parentHubConfig, new Transform());
hubInstance.addPlayer(playerRefComponent, null, Boolean.TRUE, Boolean.FALSE);
return;
ISpawnProvider spawnProvider = world.getWorldConfig().getSpawnProvider();
Transform spawnPoint = spawnProvider != null ? spawnProvider.getSpawnPoint(world, playerUUID) : null;
return world.addPlayer(playerRefComponent, spawnPoint, Boolean.TRUE, Boolean.FALSE);
}
})
.whenComplete((ret, ex) -> {
if (ex != null) {
LOGGER.at(Level.SEVERE).withCause(ex).log("Failed to teleport %s to permanent world", playerRefComponent.getUsername());
}
if (ret == null) {
if (originalWorld.isAlive()) {
originalWorld.addPlayer(playerRefComponent, originalPosition, Boolean.TRUE, Boolean.FALSE);
} else {
if (hubEntityConfig != null && hubEntityConfig.getParentHubWorldUuid() != null) {
World parentWorld = Universe.get().getWorld(hubEntityConfig.getParentHubWorldUuid());
if (parentWorld != null) {
CreativeHubWorldConfig parentHubConfig = CreativeHubWorldConfig.get(parentWorld.getWorldConfig());
if (parentHubConfig != null && parentHubConfig.getStartupInstance() != null) {
World hubInstance = CreativeHubPlugin.get().getOrSpawnHubInstance(parentWorld, parentHubConfig, new Transform());
hubInstance.addPlayer(playerRefComponent, null, Boolean.TRUE, Boolean.FALSE);
return;
}
}
}
}
World defaultWorld = Universe.get().getDefaultWorld();
if (defaultWorld != null) {
defaultWorld.addPlayer(playerRefComponent, null, Boolean.TRUE, Boolean.FALSE);
} else {
LOGGER.at(Level.SEVERE).log("No fallback world available for %s, disconnecting", playerRefComponent.getUsername());
playerRefComponent.getPacketHandler().disconnect("Failed to teleport - no world available");
World defaultWorld = Universe.get().getDefaultWorld();
if (defaultWorld != null) {
defaultWorld.addPlayer(playerRefComponent, null, Boolean.TRUE, Boolean.FALSE);
} else {
LOGGER.at(Level.SEVERE).log("No fallback world available for %s, disconnecting", playerRefComponent.getUsername());
playerRefComponent.getPacketHandler().disconnect("Failed to teleport - no world available");
}
}
}
}
});
});
}
}
}

View File

@@ -0,0 +1,66 @@
package com.hypixel.hytale.builtin.creativehub.systems;
import com.hypixel.hytale.builtin.creativehub.CreativeHubPlugin;
import com.hypixel.hytale.builtin.creativehub.config.CreativeHubEntityConfig;
import com.hypixel.hytale.builtin.creativehub.ui.ReturnToHubButtonUI;
import com.hypixel.hytale.component.AddReason;
import com.hypixel.hytale.component.CommandBuffer;
import com.hypixel.hytale.component.Ref;
import com.hypixel.hytale.component.RemoveReason;
import com.hypixel.hytale.component.Store;
import com.hypixel.hytale.component.query.Query;
import com.hypixel.hytale.component.system.RefSystem;
import com.hypixel.hytale.server.core.entity.entities.Player;
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.storage.EntityStore;
import java.util.Optional;
import javax.annotation.Nonnull;
public class ReturnToHubButtonSystem extends RefSystem<EntityStore> {
@Override
public void onEntityAdded(
@Nonnull Ref<EntityStore> ref, @Nonnull AddReason reason, @Nonnull Store<EntityStore> store, @Nonnull CommandBuffer<EntityStore> commandBuffer
) {
Optional<Boolean> isInChildWorld = this.getCreativeHubWorldStatus(store, commandBuffer, ref);
if (!isInChildWorld.isEmpty()) {
PlayerRef playerRef = commandBuffer.getComponent(ref, PlayerRef.getComponentType());
boolean disabled = !isInChildWorld.get();
ReturnToHubButtonUI.send(playerRef, disabled);
}
}
@Override
public void onEntityRemove(
@Nonnull Ref<EntityStore> ref, @Nonnull RemoveReason reason, @Nonnull Store<EntityStore> store, @Nonnull CommandBuffer<EntityStore> commandBuffer
) {
if (!this.getCreativeHubWorldStatus(store, commandBuffer, ref).isEmpty()) {
PlayerRef playerRef = commandBuffer.getComponent(ref, PlayerRef.getComponentType());
ReturnToHubButtonUI.clear(playerRef);
}
}
@Override
public Query<EntityStore> getQuery() {
return Query.and(Player.getComponentType(), PlayerRef.getComponentType());
}
private Optional<Boolean> getCreativeHubWorldStatus(
@Nonnull Store<EntityStore> store, @Nonnull CommandBuffer<EntityStore> commandBuffer, @Nonnull Ref<EntityStore> ref
) {
CreativeHubEntityConfig hubEntityConfig = commandBuffer.getComponent(ref, CreativeHubEntityConfig.getComponentType());
if (hubEntityConfig != null && hubEntityConfig.getParentHubWorldUuid() != null) {
World parentWorld = Universe.get().getWorld(hubEntityConfig.getParentHubWorldUuid());
if (parentWorld == null) {
return Optional.empty();
} else {
World currentWorld = store.getExternalData().getWorld();
World hubInstance = CreativeHubPlugin.get().getActiveHubInstance(parentWorld);
return Optional.of(!currentWorld.equals(hubInstance));
}
} else {
return Optional.empty();
}
}
}

View File

@@ -0,0 +1,87 @@
package com.hypixel.hytale.builtin.creativehub.ui;
import com.hypixel.hytale.builtin.creativehub.CreativeHubPlugin;
import com.hypixel.hytale.builtin.creativehub.config.CreativeHubEntityConfig;
import com.hypixel.hytale.builtin.creativehub.config.CreativeHubWorldConfig;
import com.hypixel.hytale.builtin.instances.InstancesPlugin;
import com.hypixel.hytale.component.Ref;
import com.hypixel.hytale.component.Store;
import com.hypixel.hytale.math.vector.Transform;
import com.hypixel.hytale.protocol.packets.interface_.CustomUIEventBindingType;
import com.hypixel.hytale.protocol.packets.interface_.UpdateAnchorUI;
import com.hypixel.hytale.server.core.modules.anchoraction.AnchorActionModule;
import com.hypixel.hytale.server.core.ui.builder.EventData;
import com.hypixel.hytale.server.core.ui.builder.UICommandBuilder;
import com.hypixel.hytale.server.core.ui.builder.UIEventBuilder;
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.spawn.ISpawnProvider;
import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public final class ReturnToHubButtonUI {
public static final String ANCHOR_ID = "MapServerContent";
public static final String ACTION_RETURN_TO_HUB = "returnToHub";
private ReturnToHubButtonUI() {
}
public static void register() {
AnchorActionModule.get().register("returnToHub", (playerRef, ref, store, data) -> executeReturnToHub(playerRef, ref, store));
}
public static void send(@Nonnull PlayerRef playerRef) {
send(playerRef, false);
}
public static void send(@Nonnull PlayerRef playerRef, boolean disabled) {
UICommandBuilder commandBuilder = new UICommandBuilder();
commandBuilder.append("Hud/ReturnToHubButton.ui");
commandBuilder.set("#ReturnToHubButton.Disabled", disabled);
UIEventBuilder eventBuilder = new UIEventBuilder();
if (!disabled) {
eventBuilder.addEventBinding(CustomUIEventBindingType.Activating, "#ReturnToHubButton", EventData.of("action", "returnToHub"), false);
}
playerRef.getPacketHandler().writeNoCache(new UpdateAnchorUI("MapServerContent", true, commandBuilder.getCommands(), eventBuilder.getEvents()));
}
public static void clear(@Nonnull PlayerRef playerRef) {
playerRef.getPacketHandler().writeNoCache(new UpdateAnchorUI("MapServerContent", true, null, null));
}
public static void executeReturnToHub(@Nonnull PlayerRef playerRef, @Nonnull Ref<EntityStore> ref, @Nonnull Store<EntityStore> store) {
World parentWorld = findParentHubWorld(store, ref);
if (parentWorld != null) {
CreativeHubWorldConfig hubConfig = CreativeHubWorldConfig.get(parentWorld.getWorldConfig());
if (hubConfig != null && hubConfig.getStartupInstance() != null) {
World world = store.getExternalData().getWorld();
World currentHub = CreativeHubPlugin.get().getActiveHubInstance(parentWorld);
if (!world.equals(currentHub)) {
ISpawnProvider spawnProvider = parentWorld.getWorldConfig().getSpawnProvider();
Transform returnPoint = spawnProvider != null ? spawnProvider.getSpawnPoint(parentWorld, playerRef.getUuid()) : new Transform();
World hubInstance = CreativeHubPlugin.get().getOrSpawnHubInstance(parentWorld, hubConfig, returnPoint);
InstancesPlugin.teleportPlayerToInstance(ref, store, hubInstance, null);
}
}
}
}
@Nullable
private static World findParentHubWorld(@Nonnull Store<EntityStore> store, @Nonnull Ref<EntityStore> ref) {
CreativeHubEntityConfig hubEntityConfig = store.getComponent(ref, CreativeHubEntityConfig.getComponentType());
if (hubEntityConfig != null && hubEntityConfig.getParentHubWorldUuid() != null) {
World parentWorld = Universe.get().getWorld(hubEntityConfig.getParentHubWorldUuid());
if (parentWorld != null) {
CreativeHubWorldConfig hubConfig = CreativeHubWorldConfig.get(parentWorld.getWorldConfig());
if (hubConfig != null && hubConfig.getStartupInstance() != null) {
return parentWorld;
}
}
}
return null;
}
}

View File

@@ -108,21 +108,21 @@ public class FluidPlugin extends JavaPlugin {
int y = ChunkUtil.minBlock(fluidSectionComponent.getY()) + ChunkUtil.yFromIndex(idx);
int z = ChunkUtil.minBlock(fluidSectionComponent.getZ()) + ChunkUtil.zFromIndex(idx);
boolean canSpread = ChunkUtil.isBorderBlock(x, z)
|| fluidSectionComponent.getFluidId(x - 1, y, z) == 0
|| fluidSectionComponent.getFluidId(x - 1, y, z) != fluidId
&& !FluidTicker.isSolid(blockMap.getAsset(blockSectionComponent.get(x - 1, y, z)))
|| fluidSectionComponent.getFluidId(x + 1, y, z) == 0
|| fluidSectionComponent.getFluidId(x + 1, y, z) != fluidId
&& !FluidTicker.isSolid(blockMap.getAsset(blockSectionComponent.get(x + 1, y, z)))
|| fluidSectionComponent.getFluidId(x, y, z - 1) == 0
|| fluidSectionComponent.getFluidId(x, y, z - 1) != fluidId
&& !FluidTicker.isSolid(blockMap.getAsset(blockSectionComponent.get(x, y, z - 1)))
|| fluidSectionComponent.getFluidId(x, y, z + 1) == 0
|| fluidSectionComponent.getFluidId(x, y, z + 1) != fluidId
&& !FluidTicker.isSolid(blockMap.getAsset(blockSectionComponent.get(x, y, z + 1)));
if (y > 0) {
if (ChunkUtil.chunkCoordinate(y) == ChunkUtil.chunkCoordinate(y - 1)) {
canSpread |= fluidSectionComponent.getFluidId(x, y - 1, z) == 0
canSpread |= fluidSectionComponent.getFluidId(x, y - 1, z) != fluidId
&& !FluidTicker.isSolid(blockMap.getAsset(blockSectionComponent.get(x, y - 1, z)));
} else {
FluidSection fluidSection2 = sections[i - 1].getComponent(FluidSection.getComponentType());
canSpread |= fluidSection2.getFluidId(x, y - 1, z) == 0
canSpread |= fluidSection2.getFluidId(x, y - 1, z) != fluidId
&& !FluidTicker.isSolid(blockMap.getAsset(blockChunkComponent.getBlock(x, y - 1, z)));
}
}

View File

@@ -19,7 +19,7 @@ import com.hypixel.hytale.component.system.tick.EntityTickingSystem;
import com.hypixel.hytale.component.system.tick.RunWhenPausedSystem;
import com.hypixel.hytale.logger.HytaleLogger;
import com.hypixel.hytale.math.util.ChunkUtil;
import com.hypixel.hytale.protocol.Packet;
import com.hypixel.hytale.protocol.ToClientPacket;
import com.hypixel.hytale.protocol.packets.world.ServerSetFluid;
import com.hypixel.hytale.protocol.packets.world.ServerSetFluids;
import com.hypixel.hytale.protocol.packets.world.SetFluidCmd;
@@ -109,7 +109,7 @@ public class FluidSystems {
Store<ChunkStore> store,
@Nonnull CommandBuffer<ChunkStore> commandBuffer,
PlayerRef query,
@Nonnull List<CompletableFuture<Packet>> results
@Nonnull List<CompletableFuture<ToClientPacket>> results
) {
ChunkColumn chunkColumnComponent = archetypeChunk.getComponent(index, this.chunkColumnComponentType);

View File

@@ -43,7 +43,7 @@ public class MultiMixDensityAsset extends DensityAsset {
ArrayList<MultiMixDensity.Key> keys = new ArrayList<>(this.keyAssets.length);
for (MultiMixDensityAsset.KeyAsset keyAsset : this.keyAssets) {
if (keyAsset.densityIndex <= 0) {
if (keyAsset.densityIndex < 0) {
keys.add(new MultiMixDensity.Key(keyAsset.value, null));
} else if (keyAsset.densityIndex >= densityInputs.size() - 1) {
LoggerUtil.getLogger()

View File

@@ -1,7 +1,7 @@
package com.hypixel.hytale.builtin.hytalegenerator.assets.patterns;
import com.hypixel.hytale.builtin.hytalegenerator.patterns.CeilingPattern;
import com.hypixel.hytale.builtin.hytalegenerator.patterns.Pattern;
import com.hypixel.hytale.builtin.hytalegenerator.patterns.SurfacePattern;
import com.hypixel.hytale.codec.KeyedCodec;
import com.hypixel.hytale.codec.builder.BuilderCodec;
import javax.annotation.Nonnull;
@@ -27,7 +27,7 @@ public class CeilingPatternAsset extends PatternAsset {
} else {
Pattern ceilingPattern = this.ceiling.build(argument);
Pattern originPattern = this.origin.build(argument);
return new CeilingPattern(ceilingPattern, originPattern);
return new SurfacePattern(ceilingPattern, originPattern, 0.0, 0.0, SurfacePattern.Facing.D, 0, 0);
}
}

View File

@@ -389,7 +389,6 @@ public class NTerrainStage implements NStage {
for (int y = this.top; y >= this.bottom; y--) {
position.y = y;
positionAbove.y = y + 1;
positionBelow.y = y - 1;
int i = y - this.bottom;
float density = this.densityBuffer.get(position);
boolean solidity = density > 0.0;
@@ -415,6 +414,8 @@ public class NTerrainStage implements NStage {
}
for (int yx = this.bottom; yx <= this.top; yx++) {
position.y = yx;
positionBelow.y = yx - 1;
int i = yx - this.bottom;
double density = this.densityBuffer.get(position);
boolean solidity = density > 0.0;

View File

@@ -1,46 +0,0 @@
package com.hypixel.hytale.builtin.hytalegenerator.patterns;
import com.hypixel.hytale.builtin.hytalegenerator.bounds.SpaceSize;
import com.hypixel.hytale.math.vector.Vector3i;
import javax.annotation.Nonnull;
public class CeilingPattern extends Pattern {
@Nonnull
private final Pattern ceilingPattern;
@Nonnull
private final Pattern airPattern;
@Nonnull
private final SpaceSize readSpaceSize;
@Nonnull
private final Vector3i rCeilingPosition;
@Nonnull
private final Pattern.Context rCeilingContext;
public CeilingPattern(@Nonnull Pattern ceilingPattern, @Nonnull Pattern airPattern) {
this.ceilingPattern = ceilingPattern;
this.airPattern = airPattern;
SpaceSize ceilingSpace = ceilingPattern.readSpace();
ceilingSpace.moveBy(new Vector3i(0, 1, 0));
this.readSpaceSize = SpaceSize.merge(ceilingSpace, airPattern.readSpace());
this.rCeilingPosition = new Vector3i();
this.rCeilingContext = new Pattern.Context();
}
@Override
public boolean matches(@Nonnull Pattern.Context context) {
this.rCeilingPosition.assign(context.position);
if (context.materialSpace.isInsideSpace(context.position) && context.materialSpace.isInsideSpace(this.rCeilingPosition)) {
this.rCeilingContext.assign(context);
this.rCeilingContext.position = this.rCeilingPosition;
return this.airPattern.matches(context) && this.ceilingPattern.matches(this.rCeilingContext);
} else {
return false;
}
}
@Nonnull
@Override
public SpaceSize readSpace() {
return this.readSpaceSize.clone();
}
}

View File

@@ -1,6 +1,7 @@
package com.hypixel.hytale.builtin.hytalegenerator.patterns;
import com.hypixel.hytale.builtin.hytalegenerator.bounds.SpaceSize;
import com.hypixel.hytale.builtin.hytalegenerator.datastructures.voxelspace.NullSpace;
import com.hypixel.hytale.builtin.hytalegenerator.datastructures.voxelspace.VoxelSpace;
import com.hypixel.hytale.builtin.hytalegenerator.material.Material;
import com.hypixel.hytale.math.vector.Vector3i;
@@ -49,12 +50,12 @@ public abstract class Pattern {
public static class Context {
@Nonnull
public Vector3i position;
@Nullable
@Nonnull
public VoxelSpace<Material> materialSpace;
public Context() {
this.position = new Vector3i();
this.materialSpace = null;
this.materialSpace = NullSpace.instance();
}
public Context(@Nonnull Vector3i position, @Nullable VoxelSpace<Material> materialSpace) {

View File

@@ -38,6 +38,7 @@ public class FieldFunctionPositionProvider extends PositionProvider {
for (FieldFunctionPositionProvider.Delimiter d : this.delimiters) {
if (d.isInside(value)) {
context.consumer.accept(p);
return;
}
}
};

View File

@@ -59,7 +59,9 @@ public class QueueProp extends Prop {
public void place(@Nonnull Prop.Context context) {
QueueProp.QueueScanResult conditionalScanResult = QueueProp.QueueScanResult.cast(context.scanResult);
if (!conditionalScanResult.isNegative()) {
conditionalScanResult.prop.place(context);
Prop.Context childContext = new Prop.Context(context);
childContext.scanResult = conditionalScanResult.propScanResult;
conditionalScanResult.prop.place(childContext);
}
}

View File

@@ -293,7 +293,9 @@ public class PrefabProp extends Prop {
Material worldMaterial = materialSpace.getContent(worldX, worldY, worldZ);
int worldMaterialHash = worldMaterial.hashMaterialIds();
if (this.materialMask.canReplace(materialHash, worldMaterialHash)) {
materialSpace.set(material, worldX, worldY, worldZ);
if (filler == 0) {
materialSpace.set(material, worldX, worldY, worldZ);
}
}
}
}

View File

@@ -179,7 +179,10 @@ public class InstancesPlugin extends JavaPlugin {
SneakyThrow.sneakyFunction(
config -> {
config.setUuid(uuid);
config.setDisplayName(WorldConfig.formatDisplayName(name));
if (config.getDisplayName() == null) {
config.setDisplayName(WorldConfig.formatDisplayName(name));
}
InstanceWorldConfig instanceConfig = InstanceWorldConfig.ensureAndGet(config);
instanceConfig.setReturnPoint(
new WorldReturnPoint(forWorld.getWorldConfig().getUuid(), returnPoint, instanceConfig.shouldPreventReconnection())
@@ -576,7 +579,7 @@ public class InstancesPlugin extends JavaPlugin {
Path instancePath = getInstanceAssetPath(name);
Universe universe = Universe.get();
WorldConfig config = WorldConfig.load(instancePath.resolve("instance.bson")).join();
IChunkStorageProvider storage = config.getChunkStorageProvider();
IChunkStorageProvider<?> storage = config.getChunkStorageProvider();
config.setChunkStorageProvider(new MigrationChunkStorageProvider(new IChunkStorageProvider[]{storage}, EmptyChunkStorageProvider.INSTANCE));
config.setResourceStorageProvider(EmptyResourceStorageProvider.INSTANCE);
config.setUuid(UUID.randomUUID());

View File

@@ -26,7 +26,6 @@ import com.hypixel.hytale.component.system.tick.EntityTickingSystem;
import com.hypixel.hytale.math.vector.Vector3f;
import com.hypixel.hytale.protocol.AnimationSlot;
import com.hypixel.hytale.protocol.BlockMount;
import com.hypixel.hytale.protocol.ComponentUpdate;
import com.hypixel.hytale.protocol.ComponentUpdateType;
import com.hypixel.hytale.protocol.GameMode;
import com.hypixel.hytale.protocol.MountController;
@@ -855,8 +854,6 @@ public class MountSystems {
private static void queueUpdatesFor(
@Nonnull Ref<EntityStore> ref, @Nonnull Map<Ref<EntityStore>, EntityTrackerSystems.EntityViewer> visibleTo, @Nonnull MountedComponent component
) {
ComponentUpdate update = new ComponentUpdate();
update.type = ComponentUpdateType.Mounted;
Ref<EntityStore> mountedToEntity = component.getMountedToEntity();
Ref<ChunkStore> mountedToBlock = component.getMountedToBlock();
Vector3f offset = component.getAttachmentOffset();
@@ -897,10 +894,8 @@ public class MountSystems {
mountedUpdate = new MountedUpdate(0, netOffset, component.getControllerType(), blockMount);
}
update.mounted = mountedUpdate;
for (EntityTrackerSystems.EntityViewer viewer : visibleTo.values()) {
viewer.queueUpdate(ref, update);
viewer.queueUpdate(ref, mountedUpdate);
}
}
}

View File

@@ -10,6 +10,7 @@ import com.hypixel.hytale.component.query.Query;
import com.hypixel.hytale.component.system.RefSystem;
import com.hypixel.hytale.protocol.packets.interaction.MountNPC;
import com.hypixel.hytale.server.core.entity.entities.Player;
import com.hypixel.hytale.server.core.modules.entity.component.Interactable;
import com.hypixel.hytale.server.core.modules.entity.damage.DeathComponent;
import com.hypixel.hytale.server.core.modules.entity.damage.DeathSystems;
import com.hypixel.hytale.server.core.modules.entity.tracker.NetworkId;
@@ -129,6 +130,7 @@ public class NPCMountSystems {
if (playerComponent != null) {
playerComponent.setMountEntityId(networkId);
playerRef.getPacketHandler().write(packet);
commandBuffer.removeComponent(ref, Interactable.getComponentType());
}
}
}
@@ -145,6 +147,7 @@ public class NPCMountSystems {
RoleChangeSystem.requestRoleChange(ref, npcComponent.getRole(), mountComponent.getOriginalRoleIndex(), false, "Idle", null, store);
commandBuffer.removeComponent(ref, this.mountComponentType);
commandBuffer.ensureComponent(ref, Interactable.getComponentType());
}
@Override

View File

@@ -30,7 +30,6 @@ import com.hypixel.hytale.server.core.asset.type.item.config.Item;
import com.hypixel.hytale.server.core.asset.type.item.config.PortalKey;
import com.hypixel.hytale.server.core.asset.type.portalworld.PillTag;
import com.hypixel.hytale.server.core.asset.type.portalworld.PortalDescription;
import com.hypixel.hytale.server.core.asset.type.portalworld.PortalSpawn;
import com.hypixel.hytale.server.core.asset.type.portalworld.PortalType;
import com.hypixel.hytale.server.core.asset.util.ColorParseUtil;
import com.hypixel.hytale.server.core.entity.UUIDComponent;
@@ -52,6 +51,8 @@ import com.hypixel.hytale.server.core.universe.world.spawn.ISpawnProvider;
import com.hypixel.hytale.server.core.universe.world.spawn.IndividualSpawnProvider;
import com.hypixel.hytale.server.core.universe.world.storage.ChunkStore;
import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
@@ -280,8 +281,7 @@ public class PortalDeviceSummonPage extends InteractiveCustomUIPage<PortalDevice
private static CompletableFuture<World> spawnReturnPortal(
@Nonnull World world, @Nonnull PortalWorld portalWorld, @Nonnull UUID sampleUuid, @Nonnull String portalBlockType
) {
PortalSpawn portalSpawn = portalWorld.getPortalType().getPortalSpawn();
return getSpawnTransform(world, sampleUuid, portalSpawn)
return getSpawnTransform(world, sampleUuid)
.thenCompose(
spawnTransform -> {
Vector3d spawnPoint = spawnTransform.getPosition();
@@ -312,21 +312,24 @@ public class PortalDeviceSummonPage extends InteractiveCustomUIPage<PortalDevice
}
@Nonnull
private static CompletableFuture<Transform> getSpawnTransform(@Nonnull World world, @Nonnull UUID sampleUuid, @Nullable PortalSpawn portalSpawn) {
private static CompletableFuture<Transform> getSpawnTransform(@Nonnull World world, @Nonnull UUID sampleUuid) {
return CompletableFuture.supplyAsync(() -> {
List<Vector3d> hintedSpawns = fetchHintedSpawns(world, sampleUuid);
return PortalSpawnFinder.computeSpawnTransform(world, hintedSpawns);
}, world);
}
private static List<Vector3d> fetchHintedSpawns(World world, UUID sampleUuid) {
ISpawnProvider spawnProvider = world.getWorldConfig().getSpawnProvider();
if (spawnProvider == null) {
return CompletableFuture.completedFuture(null);
return Collections.emptyList();
} else {
Transform worldSpawnPoint = spawnProvider.getSpawnPoint(world, sampleUuid);
if (portalSpawn == null) {
Transform uppedSpawnPoint = worldSpawnPoint.clone();
uppedSpawnPoint.getPosition().add(0.0, 0.5, 0.0);
return CompletableFuture.completedFuture(uppedSpawnPoint);
Transform[] spawnTransforms = spawnProvider.getSpawnPoints();
if (spawnTransforms != null && spawnTransforms.length > 0) {
return Arrays.stream(spawnTransforms).map(Transform::getPosition).toList();
} else {
return CompletableFuture.supplyAsync(() -> {
Transform computedSpawn = PortalSpawnFinder.computeSpawnTransform(world, portalSpawn);
return computedSpawn == null ? worldSpawnPoint : computedSpawn;
}, world);
Transform spawnPoint = spawnProvider.getSpawnPoint(world, sampleUuid);
return spawnPoint != null ? Collections.singletonList(spawnPoint.getPosition()) : Collections.emptyList();
}
}
}

View File

@@ -1,6 +1,5 @@
package com.hypixel.hytale.builtin.portals.ui;
import com.hypixel.hytale.builtin.portals.utils.posqueries.generators.SearchCircular;
import com.hypixel.hytale.builtin.portals.utils.posqueries.predicates.FitsAPortal;
import com.hypixel.hytale.component.ComponentAccessor;
import com.hypixel.hytale.component.Ref;
@@ -10,10 +9,7 @@ import com.hypixel.hytale.math.util.ChunkUtil;
import com.hypixel.hytale.math.vector.Transform;
import com.hypixel.hytale.math.vector.Vector3d;
import com.hypixel.hytale.math.vector.Vector3f;
import com.hypixel.hytale.math.vector.Vector3i;
import com.hypixel.hytale.protocol.BlockMaterial;
import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockType;
import com.hypixel.hytale.server.core.asset.type.portalworld.PortalSpawn;
import com.hypixel.hytale.server.core.modules.collision.WorldUtil;
import com.hypixel.hytale.server.core.universe.world.World;
import com.hypixel.hytale.server.core.universe.world.chunk.BlockChunk;
@@ -21,22 +17,27 @@ 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.BlockSection;
import com.hypixel.hytale.server.core.universe.world.storage.ChunkStore;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
import java.util.logging.Level;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public final class PortalSpawnFinder {
private static final int MAX_ATTEMPTS_PER_WORLD = 10;
private static final int QUALITY_ATTEMPTS = 2;
private static final int CHECKS_PER_CHUNK = 8;
private static final Vector3d FALLBACK_POSITION = Vector3d.ZERO;
@Nullable
public static Transform computeSpawnTransform(@Nonnull World world, @Nonnull PortalSpawn config) {
Vector3d spawn = findSpawnByThrowingDarts(world, config);
public static Transform computeSpawnTransform(@Nonnull World world, @Nonnull List<Vector3d> hintedSpawns) {
Vector3d spawn = guesstimateFromHints(world, hintedSpawns);
if (spawn == null) {
spawn = findFallbackPositionOnGround(world, config);
HytaleLogger.getLogger().at(Level.INFO).log("Had to use fallback spawn for portal spawn");
spawn = findFallbackPositionOnGround(world);
HytaleLogger.getLogger().atWarning().log("Had to use fallback spawn for portal spawn (10 attempts)");
}
if (spawn == null) {
HytaleLogger.getLogger().at(Level.INFO).log("Both dart and fallback spawn finder failed for portal spawn");
HytaleLogger.getLogger().atWarning().log("Both dart and fallback spawn finder failed for portal spawn");
return null;
} else {
Vector3f direction = Vector3f.lookAt(spawn).scale(-1.0F);
@@ -47,27 +48,17 @@ public final class PortalSpawnFinder {
}
@Nullable
private static Vector3d findSpawnByThrowingDarts(@Nonnull World world, @Nonnull PortalSpawn config) {
Vector3d center = config.getCenter().toVector3d();
center.setY(config.getCheckSpawnY());
int halfwayThrows = config.getChunkDartThrows() / 2;
for (int chunkDart = 0; chunkDart < config.getChunkDartThrows(); chunkDart++) {
Vector3d pointd = new SearchCircular(config.getMinRadius(), config.getMaxRadius(), 1).execute(world, center).orElse(null);
if (pointd != null) {
Vector3i point = pointd.toVector3i();
WorldChunk chunk = world.getChunk(ChunkUtil.indexChunkFromBlock(point.x, point.z));
BlockType firstBlock = chunk.getBlockType(point.x, point.y, point.z);
if (firstBlock != null) {
BlockMaterial firstBlockMat = firstBlock.getMaterial();
if (firstBlockMat != BlockMaterial.Solid) {
boolean checkIfPortalFitsNice = chunkDart < halfwayThrows;
Vector3d spawn = findGroundWithinChunk(chunk, config, checkIfPortalFitsNice);
if (spawn != null) {
HytaleLogger.getLogger().at(Level.INFO).log("Found fragment spawn at " + spawn + " after " + (chunkDart + 1) + " chunk scan(s)");
return spawn;
}
}
private static Vector3d guesstimateFromHints(World world, List<Vector3d> hintedSpawns) {
for (int i = 0; i < Math.min(hintedSpawns.size(), 10); i++) {
Vector3d hintedSpawn = hintedSpawns.get(i);
WorldChunk chunk = world.getChunk(ChunkUtil.indexChunkFromBlock(hintedSpawn.x, hintedSpawn.z));
if (chunk != null) {
boolean quality = i < 2;
int scanHeight = quality ? (int)hintedSpawn.y : 319;
Vector3d spawn = findGroundWithinChunk(chunk, scanHeight, quality);
if (spawn != null) {
HytaleLogger.getLogger().atInfo().log("Found portal spawn " + spawn + " on attempt #" + (i + 1) + " quality=" + quality);
return spawn;
}
}
}
@@ -76,15 +67,15 @@ public final class PortalSpawnFinder {
}
@Nullable
private static Vector3d findGroundWithinChunk(@Nonnull WorldChunk chunk, @Nonnull PortalSpawn config, boolean checkIfPortalFitsNice) {
private static Vector3d findGroundWithinChunk(@Nonnull WorldChunk chunk, int scanHeight, boolean checkIfPortalFitsNice) {
int chunkBlockX = ChunkUtil.minBlock(chunk.getX());
int chunkBlockZ = ChunkUtil.minBlock(chunk.getZ());
ThreadLocalRandom random = ThreadLocalRandom.current();
for (int i = 0; i < config.getChecksPerChunk(); i++) {
for (int i = 0; i < 8; i++) {
int x = chunkBlockX + random.nextInt(2, 14);
int z = chunkBlockZ + random.nextInt(2, 14);
Vector3d point = findWithGroundBelow(chunk, x, config.getCheckSpawnY(), z, config.getScanHeight(), false);
Vector3d point = findWithGroundBelow(chunk, x, scanHeight, z, scanHeight, false);
if (point != null && (!checkIfPortalFitsNice || FitsAPortal.check(chunk.getWorld(), point))) {
return point;
}
@@ -160,8 +151,8 @@ public final class PortalSpawnFinder {
}
@Nullable
private static Vector3d findFallbackPositionOnGround(@Nonnull World world, @Nonnull PortalSpawn config) {
Vector3i center = config.getCenter();
private static Vector3d findFallbackPositionOnGround(@Nonnull World world) {
Vector3d center = FALLBACK_POSITION.clone();
long chunkIndex = ChunkUtil.indexChunkFromBlock(center.x, center.z);
WorldChunk centerChunk = world.getChunk(chunkIndex);
return centerChunk == null ? null : findWithGroundBelow(centerChunk, 0, 319, 0, 319, true);

View File

@@ -0,0 +1,35 @@
package com.hypixel.hytale.builtin.randomtick;
import com.hypixel.hytale.component.Resource;
import com.hypixel.hytale.component.ResourceType;
import com.hypixel.hytale.server.core.universe.world.storage.ChunkStore;
import java.util.Random;
import javax.annotation.Nullable;
public class RandomTick implements Resource<ChunkStore> {
private int blocksPerSectionPerTickStable = 1;
private int blocksPerSectionPerTickUnstable = 3;
private Random random = new Random();
public static ResourceType<ChunkStore, RandomTick> getResourceType() {
return RandomTickPlugin.get().getRandomTickResourceType();
}
public int getBlocksPerSectionPerTickStable() {
return this.blocksPerSectionPerTickStable;
}
public int getBlocksPerSectionPerTickUnstable() {
return this.blocksPerSectionPerTickUnstable;
}
public Random getRandom() {
return this.random;
}
@Nullable
@Override
public Resource<ChunkStore> clone() {
return new RandomTick();
}
}

View File

@@ -0,0 +1,36 @@
package com.hypixel.hytale.builtin.randomtick;
import com.hypixel.hytale.builtin.randomtick.procedures.ChangeIntoBlockProcedure;
import com.hypixel.hytale.builtin.randomtick.procedures.SpreadToProcedure;
import com.hypixel.hytale.component.ResourceType;
import com.hypixel.hytale.server.core.asset.type.blocktick.config.RandomTickProcedure;
import com.hypixel.hytale.server.core.plugin.JavaPlugin;
import com.hypixel.hytale.server.core.plugin.JavaPluginInit;
import com.hypixel.hytale.server.core.universe.world.storage.ChunkStore;
import javax.annotation.Nonnull;
public class RandomTickPlugin extends JavaPlugin {
private static RandomTickPlugin INSTANCE;
private ResourceType<ChunkStore, RandomTick> randomTickResourceType;
public static RandomTickPlugin get() {
return INSTANCE;
}
public RandomTickPlugin(@Nonnull JavaPluginInit init) {
super(init);
INSTANCE = this;
}
@Override
protected void setup() {
this.randomTickResourceType = this.getChunkStoreRegistry().registerResource(RandomTick.class, RandomTick::new);
this.getChunkStoreRegistry().registerSystem(new RandomTickSystem());
RandomTickProcedure.CODEC.register("ChangeIntoBlock", ChangeIntoBlockProcedure.class, ChangeIntoBlockProcedure.CODEC);
RandomTickProcedure.CODEC.register("SpreadTo", SpreadToProcedure.class, SpreadToProcedure.CODEC);
}
public ResourceType<ChunkStore, RandomTick> getRandomTickResourceType() {
return this.randomTickResourceType;
}
}

View File

@@ -0,0 +1,114 @@
package com.hypixel.hytale.builtin.randomtick;
import com.hypixel.hytale.assetstore.map.BlockTypeAssetMap;
import com.hypixel.hytale.component.ArchetypeChunk;
import com.hypixel.hytale.component.CommandBuffer;
import com.hypixel.hytale.component.ComponentType;
import com.hypixel.hytale.component.Store;
import com.hypixel.hytale.component.query.Query;
import com.hypixel.hytale.component.system.tick.EntityTickingSystem;
import com.hypixel.hytale.math.util.ChunkUtil;
import com.hypixel.hytale.math.util.HashUtil;
import com.hypixel.hytale.server.core.asset.type.blocktick.config.RandomTickProcedure;
import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockType;
import com.hypixel.hytale.server.core.universe.world.World;
import com.hypixel.hytale.server.core.universe.world.chunk.section.BlockSection;
import com.hypixel.hytale.server.core.universe.world.chunk.section.ChunkSection;
import com.hypixel.hytale.server.core.universe.world.storage.ChunkStore;
import java.util.Random;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class RandomTickSystem extends EntityTickingSystem<ChunkStore> {
private final ComponentType<ChunkStore, BlockSection> blockSelectionComponentType = BlockSection.getComponentType();
private final ComponentType<ChunkStore, ChunkSection> chunkSectionComponentType = ChunkSection.getComponentType();
private final Query<ChunkStore> query = Query.and(this.blockSelectionComponentType, this.chunkSectionComponentType);
@Override
public void tick(
float dt,
int index,
@Nonnull ArchetypeChunk<ChunkStore> archetypeChunk,
@Nonnull Store<ChunkStore> store,
@Nonnull CommandBuffer<ChunkStore> commandBuffer
) {
BlockSection blockSection = archetypeChunk.getComponent(index, this.blockSelectionComponentType);
assert blockSection != null;
if (!blockSection.isSolidAir()) {
ChunkSection chunkSection = archetypeChunk.getComponent(index, this.chunkSectionComponentType);
assert chunkSection != null;
RandomTick config = commandBuffer.getResource(RandomTick.getResourceType());
World world = store.getExternalData().getWorld();
int interval = 32768 / config.getBlocksPerSectionPerTickStable();
long baseSeed = HashUtil.hash(world.getTick() / interval, chunkSection.getX(), chunkSection.getY(), chunkSection.getZ());
long randomSeed = (baseSeed << 1 | 1L) & 32767L;
long randomSeed2 = baseSeed >> 16 & 32767L;
long startIndex = world.getTick() % interval * config.getBlocksPerSectionPerTickStable();
BlockTypeAssetMap<String, BlockType> assetMap = BlockType.getAssetMap();
for (int i = 0; i < config.getBlocksPerSectionPerTickStable(); i++) {
int blockIndex = (int)((startIndex + i) * randomSeed + randomSeed2 & 32767L);
int localX = ChunkUtil.xFromIndex(blockIndex);
int localY = ChunkUtil.yFromIndex(blockIndex);
int localZ = ChunkUtil.zFromIndex(blockIndex);
int blockId = blockSection.get(blockIndex);
if (blockId != 0) {
BlockType blockType = assetMap.getAsset(blockId);
if (blockType != null) {
RandomTickProcedure randomTickProcedure = blockType.getRandomTickProcedure();
if (randomTickProcedure != null) {
randomTickProcedure.onRandomTick(
store,
commandBuffer,
blockSection,
ChunkUtil.worldCoordFromLocalCoord(chunkSection.getX(), localX),
ChunkUtil.worldCoordFromLocalCoord(chunkSection.getY(), localY),
ChunkUtil.worldCoordFromLocalCoord(chunkSection.getZ(), localZ),
blockId,
blockType
);
}
}
}
}
Random rng = config.getRandom();
for (int ix = 0; ix < config.getBlocksPerSectionPerTickUnstable(); ix++) {
int blockIndex = rng.nextInt(32768);
int localX = ChunkUtil.xFromIndex(blockIndex);
int localY = ChunkUtil.yFromIndex(blockIndex);
int localZ = ChunkUtil.zFromIndex(blockIndex);
int blockId = blockSection.get(blockIndex);
if (blockId != 0) {
BlockType blockType = assetMap.getAsset(blockId);
if (blockType != null) {
RandomTickProcedure randomTickProcedure = blockType.getRandomTickProcedure();
if (randomTickProcedure != null) {
randomTickProcedure.onRandomTick(
store,
commandBuffer,
blockSection,
ChunkUtil.worldCoordFromLocalCoord(chunkSection.getX(), localX),
ChunkUtil.worldCoordFromLocalCoord(chunkSection.getY(), localY),
ChunkUtil.worldCoordFromLocalCoord(chunkSection.getZ(), localZ),
blockId,
blockType
);
}
}
}
}
}
}
@Nullable
@Override
public Query<ChunkStore> getQuery() {
return this.query;
}
}

View File

@@ -0,0 +1,38 @@
package com.hypixel.hytale.builtin.randomtick.procedures;
import com.hypixel.hytale.codec.Codec;
import com.hypixel.hytale.codec.KeyedCodec;
import com.hypixel.hytale.codec.builder.BuilderCodec;
import com.hypixel.hytale.component.CommandBuffer;
import com.hypixel.hytale.component.Store;
import com.hypixel.hytale.math.util.ChunkUtil;
import com.hypixel.hytale.server.core.asset.type.blocktick.config.RandomTickProcedure;
import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockType;
import com.hypixel.hytale.server.core.universe.world.chunk.section.BlockSection;
import com.hypixel.hytale.server.core.universe.world.storage.ChunkStore;
public class ChangeIntoBlockProcedure implements RandomTickProcedure {
public static final BuilderCodec<ChangeIntoBlockProcedure> CODEC = BuilderCodec.builder(ChangeIntoBlockProcedure.class, ChangeIntoBlockProcedure::new)
.appendInherited(new KeyedCodec<>("TargetBlock", Codec.STRING), (o, i) -> o.targetBlock = i, o -> o.targetBlock, (o, p) -> o.targetBlock = p.targetBlock)
.addValidatorLate(() -> BlockType.VALIDATOR_CACHE.getValidator().late())
.add()
.build();
private String targetBlock;
@Override
public void onRandomTick(
Store<ChunkStore> store,
CommandBuffer<ChunkStore> commandBuffer,
BlockSection blockSection,
int worldX,
int worldY,
int worldZ,
int blockId,
BlockType blockType
) {
int targetBlockId = BlockType.getAssetMap().getIndex(this.targetBlock);
if (targetBlockId != Integer.MIN_VALUE) {
blockSection.set(ChunkUtil.indexBlock(worldX, worldY, worldZ), targetBlockId, 0, 0);
}
}
}

View File

@@ -0,0 +1,197 @@
package com.hypixel.hytale.builtin.randomtick.procedures;
import com.hypixel.hytale.assetstore.AssetRegistry;
import com.hypixel.hytale.codec.Codec;
import com.hypixel.hytale.codec.KeyedCodec;
import com.hypixel.hytale.codec.builder.BuilderCodec;
import com.hypixel.hytale.codec.codecs.array.ArrayCodec;
import com.hypixel.hytale.codec.validation.Validators;
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.Vector3i;
import com.hypixel.hytale.protocol.BlockMaterial;
import com.hypixel.hytale.protocol.DrawType;
import com.hypixel.hytale.server.core.asset.type.blocktick.config.RandomTickProcedure;
import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockType;
import com.hypixel.hytale.server.core.modules.time.WorldTimeResource;
import com.hypixel.hytale.server.core.universe.world.chunk.section.BlockSection;
import com.hypixel.hytale.server.core.universe.world.storage.ChunkStore;
import it.unimi.dsi.fastutil.ints.IntSet;
public class SpreadToProcedure implements RandomTickProcedure {
public static final BuilderCodec<SpreadToProcedure> CODEC = BuilderCodec.builder(SpreadToProcedure.class, SpreadToProcedure::new)
.appendInherited(
new KeyedCodec<>("SpreadDirections", new ArrayCodec<>(Vector3i.CODEC, Vector3i[]::new)),
(o, i) -> o.spreadDirections = i,
o -> o.spreadDirections,
(o, p) -> o.spreadDirections = p.spreadDirections
)
.documentation("The directions this block can spread in.")
.addValidator(Validators.nonNull())
.add()
.<Integer>appendInherited(new KeyedCodec<>("MinY", Codec.INTEGER), (o, i) -> o.minY = i, o -> o.minY, (o, p) -> o.minY = p.minY)
.documentation(
"The minimum Y level this block can spread to, relative to the current block. For example, a value of -1 means the block can spread to blocks one level below it."
)
.add()
.<Integer>appendInherited(new KeyedCodec<>("MaxY", Codec.INTEGER), (o, i) -> o.maxY = i, o -> o.maxY, (o, p) -> o.maxY = p.maxY)
.documentation(
"The maximum Y level this block can spread to, relative to the current block. For example, a value of 1 means the block can spread to blocks one level above it."
)
.add()
.<String>appendInherited(new KeyedCodec<>("AllowedTag", Codec.STRING), (o, i) -> {
o.allowedTag = i;
o.allowedTagIndex = AssetRegistry.getOrCreateTagIndex(i);
}, o -> o.allowedTag, (o, p) -> {
o.allowedTag = p.allowedTag;
o.allowedTagIndex = p.allowedTagIndex;
})
.documentation("The asset tag that the block can spread to.")
.addValidator(Validators.nonNull())
.add()
.<Boolean>appendInherited(
new KeyedCodec<>("RequireEmptyAboveTarget", Codec.BOOLEAN),
(o, i) -> o.requireEmptyAboveTarget = i,
o -> o.requireEmptyAboveTarget,
(o, p) -> o.requireEmptyAboveTarget = p.requireEmptyAboveTarget
)
.documentation("Whether the block requires an empty block above the target block to spread.")
.add()
.<Integer>appendInherited(
new KeyedCodec<>("RequiredLightLevel", Codec.INTEGER),
(o, i) -> o.requiredLightLevel = i,
o -> o.requiredLightLevel,
(o, p) -> o.requiredLightLevel = p.requiredLightLevel
)
.documentation("The minimum light level required for the block to spread.")
.addValidator(Validators.range(0, 15))
.add()
.<String>appendInherited(
new KeyedCodec<>("RevertBlock", Codec.STRING), (o, i) -> o.revertBlock = i, o -> o.revertBlock, (o, p) -> o.revertBlock = p.revertBlock
)
.documentation("If specified, the block will revert to this block if it is covered by another block.")
.addValidatorLate(() -> BlockType.VALIDATOR_CACHE.getValidator().late())
.add()
.build();
private Vector3i[] spreadDirections;
private int minY = 0;
private int maxY = 0;
private String allowedTag;
private int allowedTagIndex = Integer.MIN_VALUE;
private boolean requireEmptyAboveTarget = true;
private int requiredLightLevel = 6;
private String revertBlock;
@Override
public void onRandomTick(
Store<ChunkStore> store,
CommandBuffer<ChunkStore> commandBuffer,
BlockSection blockSection,
int worldX,
int worldY,
int worldZ,
int blockId,
BlockType blockType
) {
IntSet validSpreadTargets = BlockType.getAssetMap().getIndexesForTag(this.allowedTagIndex);
WorldTimeResource worldTimeResource = commandBuffer.getExternalData()
.getWorld()
.getEntityStore()
.getStore()
.getResource(WorldTimeResource.getResourceType());
double sunlightFactor = worldTimeResource.getSunlightFactor();
BlockSection aboveSection = blockSection;
if (!ChunkUtil.isSameChunkSection(worldX, worldY, worldZ, worldX, worldY + 1, worldZ)) {
Ref<ChunkStore> aboveChunk = store.getExternalData()
.getChunkSectionReference(
commandBuffer, ChunkUtil.chunkCoordinate(worldX), ChunkUtil.chunkCoordinate(worldY + 1), ChunkUtil.chunkCoordinate(worldZ)
);
if (aboveChunk == null) {
return;
}
BlockSection aboveBlockSection = commandBuffer.getComponent(aboveChunk, BlockSection.getComponentType());
if (aboveBlockSection == null) {
return;
}
aboveSection = aboveBlockSection;
}
int aboveIndex = ChunkUtil.indexBlock(worldX, worldY + 1, worldZ);
if (this.revertBlock != null) {
int blockAtAboveId = aboveSection.get(aboveIndex);
BlockType blockAtAbove = BlockType.getAssetMap().getAsset(blockAtAboveId);
if (blockAtAbove != null && (blockAtAbove.getDrawType() == DrawType.Cube || blockAtAbove.getDrawType() == DrawType.CubeWithModel)) {
int revert = BlockType.getAssetMap().getIndex(this.revertBlock);
if (revert != Integer.MIN_VALUE) {
blockSection.set(worldX, worldY, worldZ, revert, 0, 0);
return;
}
}
}
int skyLight = (int)(aboveSection.getLocalLight().getSkyLight(aboveIndex) * sunlightFactor);
int blockLevel = aboveSection.getLocalLight().getBlockLightIntensity(aboveIndex);
int lightLevel = Math.max(skyLight, blockLevel);
if (lightLevel >= this.requiredLightLevel) {
for (int y = this.minY; y <= this.maxY; y++) {
for (Vector3i direction : this.spreadDirections) {
int targetX = worldX + direction.x;
int targetY = worldY + direction.y + y;
int targetZ = worldZ + direction.z;
BlockSection targetBlockSection = blockSection;
if (!ChunkUtil.isSameChunkSection(worldX, worldY, worldZ, targetX, targetY, targetZ)) {
Ref<ChunkStore> otherChunk = store.getExternalData()
.getChunkSectionReference(
commandBuffer, ChunkUtil.chunkCoordinate(targetX), ChunkUtil.chunkCoordinate(targetY), ChunkUtil.chunkCoordinate(targetZ)
);
if (otherChunk == null) {
continue;
}
targetBlockSection = commandBuffer.getComponent(otherChunk, BlockSection.getComponentType());
if (targetBlockSection == null) {
continue;
}
}
int targetIndex = ChunkUtil.indexBlock(targetX, targetY, targetZ);
int targetBlockId = targetBlockSection.get(targetIndex);
if (validSpreadTargets.contains(targetBlockId)) {
if (this.requireEmptyAboveTarget) {
int aboveTargetBlockId;
if (ChunkUtil.isSameChunkSection(targetX, targetY, targetZ, targetX, targetY + 1, targetZ)) {
aboveTargetBlockId = targetBlockSection.get(ChunkUtil.indexBlock(targetX, targetY + 1, targetZ));
} else {
Ref<ChunkStore> aboveChunkx = store.getExternalData()
.getChunkSectionReference(
commandBuffer, ChunkUtil.chunkCoordinate(targetX), ChunkUtil.chunkCoordinate(targetY + 1), ChunkUtil.chunkCoordinate(targetZ)
);
if (aboveChunkx == null) {
continue;
}
BlockSection aboveBlockSection = commandBuffer.getComponent(aboveChunkx, BlockSection.getComponentType());
if (aboveBlockSection == null) {
continue;
}
aboveTargetBlockId = aboveBlockSection.get(ChunkUtil.indexBlock(targetX, targetY + 1, targetZ));
}
BlockType aboveBlockType = BlockType.getAssetMap().getAsset(aboveTargetBlockId);
if (aboveBlockType == null || aboveBlockType.getMaterial() != BlockMaterial.Empty) {
continue;
}
}
targetBlockSection.set(targetIndex, blockId, 0, 0);
}
}
}
}
}
}

View File

@@ -51,57 +51,69 @@ public class TeleportOtherToPlayerCommand extends CommandBase {
World targetWorld = targetStore.getExternalData().getWorld();
sourceWorld.execute(
() -> {
TransformComponent transformComponent = sourceStore.getComponent(sourceRef, TransformComponent.getComponentType());
if (!sourceRef.isValid()) {
context.sendMessage(MESSAGE_COMMANDS_ERRORS_PLAYER_NOT_IN_WORLD);
} else if (!targetRef.isValid()) {
context.sendMessage(MESSAGE_COMMANDS_ERRORS_TARGET_NOT_IN_WORLD);
} else {
TransformComponent transformComponent = sourceStore.getComponent(sourceRef, TransformComponent.getComponentType());
assert transformComponent != null;
assert transformComponent != null;
HeadRotation headRotationComponent = sourceStore.getComponent(sourceRef, HeadRotation.getComponentType());
HeadRotation headRotationComponent = sourceStore.getComponent(sourceRef, HeadRotation.getComponentType());
assert headRotationComponent != null;
assert headRotationComponent != null;
Vector3d pos = transformComponent.getPosition().clone();
Vector3f rotation = headRotationComponent.getRotation().clone();
targetWorld.execute(
() -> {
TransformComponent targetTransformComponent = targetStore.getComponent(targetRef, TransformComponent.getComponentType());
Vector3d pos = transformComponent.getPosition().clone();
Vector3f rotation = headRotationComponent.getRotation().clone();
targetWorld.execute(
() -> {
TransformComponent targetTransformComponent = targetStore.getComponent(targetRef, TransformComponent.getComponentType());
assert targetTransformComponent != null;
assert targetTransformComponent != null;
HeadRotation targetHeadRotationComponent = targetStore.getComponent(targetRef, HeadRotation.getComponentType());
HeadRotation targetHeadRotationComponent = targetStore.getComponent(targetRef, HeadRotation.getComponentType());
assert targetHeadRotationComponent != null;
assert targetHeadRotationComponent != null;
Vector3d targetPosition = targetTransformComponent.getPosition().clone();
Vector3f targetHeadRotation = targetHeadRotationComponent.getRotation().clone();
Transform targetTransform = new Transform(targetPosition, targetHeadRotation);
sourceWorld.execute(
() -> {
Teleport teleportComponent = Teleport.createForPlayer(targetWorld, targetTransform);
sourceStore.addComponent(sourceRef, Teleport.getComponentType(), teleportComponent);
PlayerRef sourcePlayerRefComponent = sourceStore.getComponent(sourceRef, PlayerRef.getComponentType());
Vector3d targetPosition = targetTransformComponent.getPosition().clone();
Vector3f targetHeadRotation = targetHeadRotationComponent.getRotation().clone();
Transform targetTransform = new Transform(targetPosition, targetHeadRotation);
sourceWorld.execute(
() -> {
if (!sourceRef.isValid()) {
context.sendMessage(MESSAGE_COMMANDS_ERRORS_PLAYER_NOT_IN_WORLD);
} else if (!targetRef.isValid()) {
context.sendMessage(MESSAGE_COMMANDS_ERRORS_TARGET_NOT_IN_WORLD);
} else {
Teleport teleportComponent = Teleport.createForPlayer(targetWorld, targetTransform);
sourceStore.addComponent(sourceRef, Teleport.getComponentType(), teleportComponent);
PlayerRef sourcePlayerRefComponent = sourceStore.getComponent(sourceRef, PlayerRef.getComponentType());
assert sourcePlayerRefComponent != null;
assert sourcePlayerRefComponent != null;
PlayerRef targetPlayerRefComponent = targetStore.getComponent(targetRef, PlayerRef.getComponentType());
PlayerRef targetPlayerRefComponent = targetStore.getComponent(targetRef, PlayerRef.getComponentType());
assert targetPlayerRefComponent != null;
assert targetPlayerRefComponent != null;
context.sendMessage(
Message.translation("server.commands.teleport.teleportedOtherToPlayer")
.param("targetName", sourcePlayerRefComponent.getUsername())
.param("toName", targetPlayerRefComponent.getUsername())
);
sourceStore.ensureAndGetComponent(sourceRef, TeleportHistory.getComponentType())
.append(
sourceWorld,
pos,
rotation,
"Teleport to " + targetPlayerRefComponent.getUsername() + " by " + context.sender().getDisplayName()
);
}
);
}
);
context.sendMessage(
Message.translation("server.commands.teleport.teleportedOtherToPlayer")
.param("targetName", sourcePlayerRefComponent.getUsername())
.param("toName", targetPlayerRefComponent.getUsername())
);
sourceStore.ensureAndGetComponent(sourceRef, TeleportHistory.getComponentType())
.append(
sourceWorld,
pos,
rotation,
"Teleport to " + targetPlayerRefComponent.getUsername() + " by " + context.sender().getDisplayName()
);
}
}
);
}
);
}
}
);
} else {

View File

@@ -1,19 +0,0 @@
package com.hypixel.hytale.builtin.worldgen;
import com.hypixel.hytale.server.worldgen.util.LogUtil;
import java.util.logging.Level;
import javax.annotation.Nonnull;
public interface FeatureFlags {
@Deprecated(since = "2026-01-19", forRemoval = true)
boolean VERSION_OVERRIDES = of("hytale.worldgen.version_overrides");
static boolean of(@Nonnull String featureFlag) {
if (System.getProperty(featureFlag) == null && System.getenv(featureFlag) == null) {
return false;
} else {
LogUtil.getLogger().at(Level.INFO).log("Feature %s is enabled.", featureFlag);
return true;
}
}
}

View File

@@ -49,15 +49,17 @@ public class WorldGenPlugin extends JavaPlugin {
instance = this;
this.getEntityStoreRegistry().registerSystem(new BiomeDataSystem());
IWorldGenProvider.CODEC.register(Priority.DEFAULT.before(1), "Hytale", HytaleWorldGenProvider.class, HytaleWorldGenProvider.CODEC);
FileIO.setDefaultRoot(AssetModule.get().getBaseAssetPack().getRoot());
if (FeatureFlags.VERSION_OVERRIDES) {
AssetModule assets = AssetModule.get();
AssetModule assets = AssetModule.get();
if (assets.getAssetPacks().isEmpty()) {
this.getLogger().at(Level.SEVERE).log("No asset packs loaded");
} else {
FileIO.setDefaultRoot(assets.getBaseAssetPack().getRoot());
List<WorldGenPlugin.Version> packs = loadVersionPacks(assets);
Object2ObjectOpenHashMap<String, Semver> versions = new Object2ObjectOpenHashMap<>();
for (WorldGenPlugin.Version version : packs) {
validateVersion(version, packs);
assets.registerPack(version.getPackName(), version.path, version.manifest);
assets.registerPack(version.getPackName(), version.path, version.manifest, false);
Semver latest = versions.get(version.name);
if (latest == null || version.manifest.getVersion().compareTo(latest) > 0) {
versions.put(version.name, version.manifest.getVersion());

View File

@@ -315,7 +315,7 @@ public class BuilderCodec<T> implements Codec<T>, DirectDecodeCodec<T>, RawJsonC
}
}
public void decodeJson0(@Nonnull RawJsonReader reader, T t, ExtraInfo extraInfo) throws IOException {
private void decodeJson0(@Nonnull RawJsonReader reader, T t, ExtraInfo extraInfo) throws IOException {
reader.expect('{');
reader.consumeWhiteSpace();
if (!reader.tryConsume('}')) {

View File

@@ -426,15 +426,19 @@ public class StringUtil {
public static String toPaddedBinaryString(int val) {
byte[] buf = new byte[]{48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48};
int leadingZeros = Integer.numberOfLeadingZeros(val);
int mag = 32 - leadingZeros;
int pos = Math.max(mag, 1);
if (leadingZeros == 32) {
return new String(buf, 0);
} else {
int mag = 32 - leadingZeros;
int pos = Math.max(mag, 1);
do {
buf[leadingZeros + --pos] = (byte)(48 + (val & 1));
val >>>= 1;
} while (pos > 0);
do {
buf[leadingZeros + --pos] = (byte)(48 + (val & 1));
val >>>= 1;
} while (pos > 0);
return new String(buf, 0);
return new String(buf, 0);
}
}
@Nonnull

View File

@@ -13,6 +13,7 @@ public class ChunkUtil {
public static final int SIZE_COLUMNS = 1024;
public static final int SIZE_COLUMNS_MASK = 1023;
public static final int SIZE_BLOCKS = 32768;
public static final int SIZE_BLOCKS_MASK = 32767;
public static final int BITS2 = 10;
public static final int NON_CHUNK_MASK = -32;
public static final int HEIGHT_SECTIONS = 10;

View File

@@ -29,7 +29,7 @@ public interface FileIO {
}
@Nonnull
static FileIOSystem openFileIOSystem(@Nonnull FileIOSystem fs) {
static <FS extends FileIOSystem> FS openFileIOSystem(@Nonnull FS fs) {
FileIOSystem.Provider.set(fs);
return fs;
}
@@ -71,16 +71,20 @@ public interface FileIO {
Path assetDirPath = relativize(path, fs.baseRoot());
ObjectArrayList<AssetPath> paths = new ObjectArrayList<>();
ObjectOpenHashSet<AssetPath> visited = new ObjectOpenHashSet<>();
ObjectOpenHashSet<AssetPath> disabled = new ObjectOpenHashSet<>();
for (Path root : fs.roots().paths) {
Path rootAssetDirPath = append(root, assetDirPath);
if (Files.exists(rootAssetDirPath) && Files.isDirectory(rootAssetDirPath)) {
try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(rootAssetDirPath)) {
visited.addAll(disabled);
disabled.clear();
for (Path filepath : dirStream) {
AssetPath assetPath = AssetPath.fromAbsolute(root, filepath);
AssetPath disabledPath = disableOp.apply(assetPath);
if (disabledPath != assetPath) {
visited.add(disabledPath);
disabled.add(disabledPath);
} else if (matcher.test(assetPath) && visited.add(assetPath)) {
paths.add(assetPath);
}

View File

@@ -0,0 +1,179 @@
package com.hypixel.hytale.protocol;
import com.hypixel.hytale.protocol.io.PacketIO;
import com.hypixel.hytale.protocol.io.ProtocolException;
import com.hypixel.hytale.protocol.io.ValidationResult;
import com.hypixel.hytale.protocol.io.VarInt;
import io.netty.buffer.ByteBuf;
import java.util.Arrays;
import javax.annotation.Nonnull;
public class ActiveAnimationsUpdate extends ComponentUpdate {
public static final int NULLABLE_BIT_FIELD_SIZE = 0;
public static final int FIXED_BLOCK_SIZE = 0;
public static final int VARIABLE_FIELD_COUNT = 1;
public static final int VARIABLE_BLOCK_START = 0;
public static final int MAX_SIZE = 1677721600;
@Nonnull
public String[] activeAnimations = new String[0];
public ActiveAnimationsUpdate() {
}
public ActiveAnimationsUpdate(@Nonnull String[] activeAnimations) {
this.activeAnimations = activeAnimations;
}
public ActiveAnimationsUpdate(@Nonnull ActiveAnimationsUpdate other) {
this.activeAnimations = other.activeAnimations;
}
@Nonnull
public static ActiveAnimationsUpdate deserialize(@Nonnull ByteBuf buf, int offset) {
ActiveAnimationsUpdate obj = new ActiveAnimationsUpdate();
int pos = offset + 0;
int activeAnimationsCount = VarInt.peek(buf, pos);
if (activeAnimationsCount < 0) {
throw ProtocolException.negativeLength("ActiveAnimations", activeAnimationsCount);
} else if (activeAnimationsCount > 4096000) {
throw ProtocolException.arrayTooLong("ActiveAnimations", activeAnimationsCount, 4096000);
} else {
pos += VarInt.size(activeAnimationsCount);
int activeAnimationsBitfieldSize = (activeAnimationsCount + 7) / 8;
byte[] activeAnimationsBitfield = PacketIO.readBytes(buf, pos, activeAnimationsBitfieldSize);
pos += activeAnimationsBitfieldSize;
obj.activeAnimations = new String[activeAnimationsCount];
for (int i = 0; i < activeAnimationsCount; i++) {
if ((activeAnimationsBitfield[i / 8] & 1 << i % 8) != 0) {
int strLen = VarInt.peek(buf, pos);
if (strLen < 0) {
throw ProtocolException.negativeLength("activeAnimations[" + i + "]", strLen);
}
if (strLen > 4096000) {
throw ProtocolException.stringTooLong("activeAnimations[" + i + "]", strLen, 4096000);
}
int strVarLen = VarInt.length(buf, pos);
obj.activeAnimations[i] = PacketIO.readVarString(buf, pos);
pos += strVarLen + strLen;
}
}
return obj;
}
}
public static int computeBytesConsumed(@Nonnull ByteBuf buf, int offset) {
int pos = offset + 0;
int arrLen = VarInt.peek(buf, pos);
pos += VarInt.length(buf, pos);
int bitfieldSize = (arrLen + 7) / 8;
byte[] bitfield = PacketIO.readBytes(buf, pos, bitfieldSize);
pos += bitfieldSize;
for (int i = 0; i < arrLen; i++) {
if ((bitfield[i / 8] & 1 << i % 8) != 0) {
int sl = VarInt.peek(buf, pos);
pos += VarInt.length(buf, pos) + sl;
}
}
return pos - offset;
}
@Override
public int serialize(@Nonnull ByteBuf buf) {
int startPos = buf.writerIndex();
if (this.activeAnimations.length > 4096000) {
throw ProtocolException.arrayTooLong("ActiveAnimations", this.activeAnimations.length, 4096000);
} else {
VarInt.write(buf, this.activeAnimations.length);
int activeAnimationsBitfieldSize = (this.activeAnimations.length + 7) / 8;
byte[] activeAnimationsBitfield = new byte[activeAnimationsBitfieldSize];
for (int i = 0; i < this.activeAnimations.length; i++) {
if (this.activeAnimations[i] != null) {
activeAnimationsBitfield[i / 8] = (byte)(activeAnimationsBitfield[i / 8] | (byte)(1 << i % 8));
}
}
buf.writeBytes(activeAnimationsBitfield);
for (int ix = 0; ix < this.activeAnimations.length; ix++) {
if (this.activeAnimations[ix] != null) {
PacketIO.writeVarString(buf, this.activeAnimations[ix], 4096000);
}
}
return buf.writerIndex() - startPos;
}
}
@Override
public int computeSize() {
int size = 0;
int activeAnimationsSize = 0;
for (String elem : this.activeAnimations) {
if (elem != null) {
activeAnimationsSize += PacketIO.stringSize(elem);
}
}
return size + VarInt.size(this.activeAnimations.length) + (this.activeAnimations.length + 7) / 8 + activeAnimationsSize;
}
public static ValidationResult validateStructure(@Nonnull ByteBuf buffer, int offset) {
if (buffer.readableBytes() - offset < 0) {
return ValidationResult.error("Buffer too small: expected at least 0 bytes");
} else {
int pos = offset + 0;
int activeAnimationsCount = VarInt.peek(buffer, pos);
if (activeAnimationsCount < 0) {
return ValidationResult.error("Invalid array count for ActiveAnimations");
} else if (activeAnimationsCount > 4096000) {
return ValidationResult.error("ActiveAnimations exceeds max length 4096000");
} else {
pos += VarInt.length(buffer, pos);
for (int i = 0; i < activeAnimationsCount; i++) {
int strLen = VarInt.peek(buffer, pos);
if (strLen < 0) {
return ValidationResult.error("Invalid string length in ActiveAnimations");
}
pos += VarInt.length(buffer, pos);
pos += strLen;
if (pos > buffer.writerIndex()) {
return ValidationResult.error("Buffer overflow reading string in ActiveAnimations");
}
}
return ValidationResult.OK;
}
}
}
public ActiveAnimationsUpdate clone() {
ActiveAnimationsUpdate copy = new ActiveAnimationsUpdate();
copy.activeAnimations = Arrays.copyOf(this.activeAnimations, this.activeAnimations.length);
return copy;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
} else {
return obj instanceof ActiveAnimationsUpdate other ? Arrays.equals((Object[])this.activeAnimations, (Object[])other.activeAnimations) : false;
}
}
@Override
public int hashCode() {
int result = 1;
return 31 * result + Arrays.hashCode((Object[])this.activeAnimations);
}
}

View File

@@ -0,0 +1,124 @@
package com.hypixel.hytale.protocol;
import com.hypixel.hytale.protocol.io.ProtocolException;
import com.hypixel.hytale.protocol.io.ValidationResult;
import com.hypixel.hytale.protocol.io.VarInt;
import io.netty.buffer.ByteBuf;
import java.util.Arrays;
import javax.annotation.Nonnull;
public class AudioUpdate extends ComponentUpdate {
public static final int NULLABLE_BIT_FIELD_SIZE = 0;
public static final int FIXED_BLOCK_SIZE = 0;
public static final int VARIABLE_FIELD_COUNT = 1;
public static final int VARIABLE_BLOCK_START = 0;
public static final int MAX_SIZE = 16384005;
@Nonnull
public int[] soundEventIds = new int[0];
public AudioUpdate() {
}
public AudioUpdate(@Nonnull int[] soundEventIds) {
this.soundEventIds = soundEventIds;
}
public AudioUpdate(@Nonnull AudioUpdate other) {
this.soundEventIds = other.soundEventIds;
}
@Nonnull
public static AudioUpdate deserialize(@Nonnull ByteBuf buf, int offset) {
AudioUpdate obj = new AudioUpdate();
int pos = offset + 0;
int soundEventIdsCount = VarInt.peek(buf, pos);
if (soundEventIdsCount < 0) {
throw ProtocolException.negativeLength("SoundEventIds", soundEventIdsCount);
} else if (soundEventIdsCount > 4096000) {
throw ProtocolException.arrayTooLong("SoundEventIds", soundEventIdsCount, 4096000);
} else {
int soundEventIdsVarLen = VarInt.size(soundEventIdsCount);
if (pos + soundEventIdsVarLen + soundEventIdsCount * 4L > buf.readableBytes()) {
throw ProtocolException.bufferTooSmall("SoundEventIds", pos + soundEventIdsVarLen + soundEventIdsCount * 4, buf.readableBytes());
} else {
pos += soundEventIdsVarLen;
obj.soundEventIds = new int[soundEventIdsCount];
for (int i = 0; i < soundEventIdsCount; i++) {
obj.soundEventIds[i] = buf.getIntLE(pos + i * 4);
}
pos += soundEventIdsCount * 4;
return obj;
}
}
}
public static int computeBytesConsumed(@Nonnull ByteBuf buf, int offset) {
int pos = offset + 0;
int arrLen = VarInt.peek(buf, pos);
pos += VarInt.length(buf, pos) + arrLen * 4;
return pos - offset;
}
@Override
public int serialize(@Nonnull ByteBuf buf) {
int startPos = buf.writerIndex();
if (this.soundEventIds.length > 4096000) {
throw ProtocolException.arrayTooLong("SoundEventIds", this.soundEventIds.length, 4096000);
} else {
VarInt.write(buf, this.soundEventIds.length);
for (int item : this.soundEventIds) {
buf.writeIntLE(item);
}
return buf.writerIndex() - startPos;
}
}
@Override
public int computeSize() {
int size = 0;
return size + VarInt.size(this.soundEventIds.length) + this.soundEventIds.length * 4;
}
public static ValidationResult validateStructure(@Nonnull ByteBuf buffer, int offset) {
if (buffer.readableBytes() - offset < 0) {
return ValidationResult.error("Buffer too small: expected at least 0 bytes");
} else {
int pos = offset + 0;
int soundEventIdsCount = VarInt.peek(buffer, pos);
if (soundEventIdsCount < 0) {
return ValidationResult.error("Invalid array count for SoundEventIds");
} else if (soundEventIdsCount > 4096000) {
return ValidationResult.error("SoundEventIds exceeds max length 4096000");
} else {
pos += VarInt.length(buffer, pos);
pos += soundEventIdsCount * 4;
return pos > buffer.writerIndex() ? ValidationResult.error("Buffer overflow reading SoundEventIds") : ValidationResult.OK;
}
}
}
public AudioUpdate clone() {
AudioUpdate copy = new AudioUpdate();
copy.soundEventIds = Arrays.copyOf(this.soundEventIds, this.soundEventIds.length);
return copy;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
} else {
return obj instanceof AudioUpdate other ? Arrays.equals(this.soundEventIds, other.soundEventIds) : false;
}
}
@Override
public int hashCode() {
int result = 1;
return 31 * result + Arrays.hashCode(this.soundEventIds);
}
}

View File

@@ -18,8 +18,8 @@ public class BenchRequirement {
public static final int MAX_SIZE = 1677721600;
@Nonnull
public BenchType type = BenchType.Crafting;
@Nullable
public String id;
@Nonnull
public String id = "";
@Nullable
public String[] categories;
public int requiredTierLevel;
@@ -27,7 +27,7 @@ public class BenchRequirement {
public BenchRequirement() {
}
public BenchRequirement(@Nonnull BenchType type, @Nullable String id, @Nullable String[] categories, int requiredTierLevel) {
public BenchRequirement(@Nonnull BenchType type, @Nonnull String id, @Nullable String[] categories, int requiredTierLevel) {
this.type = type;
this.id = id;
this.categories = categories;
@@ -47,84 +47,77 @@ public class BenchRequirement {
byte nullBits = buf.getByte(offset);
obj.type = BenchType.fromValue(buf.getByte(offset + 1));
obj.requiredTierLevel = buf.getIntLE(offset + 2);
if ((nullBits & 1) != 0) {
int varPos0 = offset + 14 + buf.getIntLE(offset + 6);
int idLen = VarInt.peek(buf, varPos0);
if (idLen < 0) {
throw ProtocolException.negativeLength("Id", idLen);
}
if (idLen > 4096000) {
throw ProtocolException.stringTooLong("Id", idLen, 4096000);
}
int varPos0 = offset + 14 + buf.getIntLE(offset + 6);
int idLen = VarInt.peek(buf, varPos0);
if (idLen < 0) {
throw ProtocolException.negativeLength("Id", idLen);
} else if (idLen > 4096000) {
throw ProtocolException.stringTooLong("Id", idLen, 4096000);
} else {
obj.id = PacketIO.readVarString(buf, varPos0, PacketIO.UTF8);
}
if ((nullBits & 2) != 0) {
int varPos1 = offset + 14 + buf.getIntLE(offset + 10);
int categoriesCount = VarInt.peek(buf, varPos1);
if (categoriesCount < 0) {
throw ProtocolException.negativeLength("Categories", categoriesCount);
}
if (categoriesCount > 4096000) {
throw ProtocolException.arrayTooLong("Categories", categoriesCount, 4096000);
}
int varIntLen = VarInt.length(buf, varPos1);
if (varPos1 + varIntLen + categoriesCount * 1L > buf.readableBytes()) {
throw ProtocolException.bufferTooSmall("Categories", varPos1 + varIntLen + categoriesCount * 1, buf.readableBytes());
}
obj.categories = new String[categoriesCount];
int elemPos = varPos1 + varIntLen;
for (int i = 0; i < categoriesCount; i++) {
int strLen = VarInt.peek(buf, elemPos);
if (strLen < 0) {
throw ProtocolException.negativeLength("categories[" + i + "]", strLen);
if ((nullBits & 1) != 0) {
varPos0 = offset + 14 + buf.getIntLE(offset + 10);
idLen = VarInt.peek(buf, varPos0);
if (idLen < 0) {
throw ProtocolException.negativeLength("Categories", idLen);
}
if (strLen > 4096000) {
throw ProtocolException.stringTooLong("categories[" + i + "]", strLen, 4096000);
if (idLen > 4096000) {
throw ProtocolException.arrayTooLong("Categories", idLen, 4096000);
}
int strVarLen = VarInt.length(buf, elemPos);
obj.categories[i] = PacketIO.readVarString(buf, elemPos);
elemPos += strVarLen + strLen;
}
}
int varIntLen = VarInt.length(buf, varPos0);
if (varPos0 + varIntLen + idLen * 1L > buf.readableBytes()) {
throw ProtocolException.bufferTooSmall("Categories", varPos0 + varIntLen + idLen * 1, buf.readableBytes());
}
return obj;
obj.categories = new String[idLen];
int elemPos = varPos0 + varIntLen;
for (int i = 0; i < idLen; i++) {
int strLen = VarInt.peek(buf, elemPos);
if (strLen < 0) {
throw ProtocolException.negativeLength("categories[" + i + "]", strLen);
}
if (strLen > 4096000) {
throw ProtocolException.stringTooLong("categories[" + i + "]", strLen, 4096000);
}
int strVarLen = VarInt.length(buf, elemPos);
obj.categories[i] = PacketIO.readVarString(buf, elemPos);
elemPos += strVarLen + strLen;
}
}
return obj;
}
}
public static int computeBytesConsumed(@Nonnull ByteBuf buf, int offset) {
byte nullBits = buf.getByte(offset);
int maxEnd = 14;
if ((nullBits & 1) != 0) {
int fieldOffset0 = buf.getIntLE(offset + 6);
int pos0 = offset + 14 + fieldOffset0;
int sl = VarInt.peek(buf, pos0);
pos0 += VarInt.length(buf, pos0) + sl;
if (pos0 - offset > maxEnd) {
maxEnd = pos0 - offset;
}
int fieldOffset0 = buf.getIntLE(offset + 6);
int pos0 = offset + 14 + fieldOffset0;
int sl = VarInt.peek(buf, pos0);
pos0 += VarInt.length(buf, pos0) + sl;
if (pos0 - offset > maxEnd) {
maxEnd = pos0 - offset;
}
if ((nullBits & 2) != 0) {
int fieldOffset1 = buf.getIntLE(offset + 10);
int pos1 = offset + 14 + fieldOffset1;
int arrLen = VarInt.peek(buf, pos1);
pos1 += VarInt.length(buf, pos1);
if ((nullBits & 1) != 0) {
fieldOffset0 = buf.getIntLE(offset + 10);
pos0 = offset + 14 + fieldOffset0;
sl = VarInt.peek(buf, pos0);
pos0 += VarInt.length(buf, pos0);
for (int i = 0; i < arrLen; i++) {
int sl = VarInt.peek(buf, pos1);
pos1 += VarInt.length(buf, pos1) + sl;
for (int i = 0; i < sl; i++) {
int slx = VarInt.peek(buf, pos0);
pos0 += VarInt.length(buf, pos0) + slx;
}
if (pos1 - offset > maxEnd) {
maxEnd = pos1 - offset;
if (pos0 - offset > maxEnd) {
maxEnd = pos0 - offset;
}
}
@@ -134,12 +127,8 @@ public class BenchRequirement {
public void serialize(@Nonnull ByteBuf buf) {
int startPos = buf.writerIndex();
byte nullBits = 0;
if (this.id != null) {
nullBits = (byte)(nullBits | 1);
}
if (this.categories != null) {
nullBits = (byte)(nullBits | 2);
nullBits = (byte)(nullBits | 1);
}
buf.writeByte(nullBits);
@@ -150,13 +139,8 @@ public class BenchRequirement {
int categoriesOffsetSlot = buf.writerIndex();
buf.writeIntLE(0);
int varBlockStart = buf.writerIndex();
if (this.id != null) {
buf.setIntLE(idOffsetSlot, buf.writerIndex() - varBlockStart);
PacketIO.writeVarString(buf, this.id, 4096000);
} else {
buf.setIntLE(idOffsetSlot, -1);
}
buf.setIntLE(idOffsetSlot, buf.writerIndex() - varBlockStart);
PacketIO.writeVarString(buf, this.id, 4096000);
if (this.categories != null) {
buf.setIntLE(categoriesOffsetSlot, buf.writerIndex() - varBlockStart);
if (this.categories.length > 4096000) {
@@ -175,10 +159,7 @@ public class BenchRequirement {
public int computeSize() {
int size = 14;
if (this.id != null) {
size += PacketIO.stringSize(this.id);
}
size += PacketIO.stringSize(this.id);
if (this.categories != null) {
int categoriesSize = 0;
@@ -197,70 +178,66 @@ public class BenchRequirement {
return ValidationResult.error("Buffer too small: expected at least 14 bytes");
} else {
byte nullBits = buffer.getByte(offset);
if ((nullBits & 1) != 0) {
int idOffset = buffer.getIntLE(offset + 6);
if (idOffset < 0) {
return ValidationResult.error("Invalid offset for Id");
}
int idOffset = buffer.getIntLE(offset + 6);
if (idOffset < 0) {
return ValidationResult.error("Invalid offset for Id");
} else {
int pos = offset + 14 + idOffset;
if (pos >= buffer.writerIndex()) {
return ValidationResult.error("Offset out of bounds for Id");
}
} else {
int idLen = VarInt.peek(buffer, pos);
if (idLen < 0) {
return ValidationResult.error("Invalid string length for Id");
} else if (idLen > 4096000) {
return ValidationResult.error("Id exceeds max length 4096000");
} else {
pos += VarInt.length(buffer, pos);
pos += idLen;
if (pos > buffer.writerIndex()) {
return ValidationResult.error("Buffer overflow reading Id");
} else {
if ((nullBits & 1) != 0) {
idOffset = buffer.getIntLE(offset + 10);
if (idOffset < 0) {
return ValidationResult.error("Invalid offset for Categories");
}
int idLen = VarInt.peek(buffer, pos);
if (idLen < 0) {
return ValidationResult.error("Invalid string length for Id");
}
pos = offset + 14 + idOffset;
if (pos >= buffer.writerIndex()) {
return ValidationResult.error("Offset out of bounds for Categories");
}
if (idLen > 4096000) {
return ValidationResult.error("Id exceeds max length 4096000");
}
idLen = VarInt.peek(buffer, pos);
if (idLen < 0) {
return ValidationResult.error("Invalid array count for Categories");
}
pos += VarInt.length(buffer, pos);
pos += idLen;
if (pos > buffer.writerIndex()) {
return ValidationResult.error("Buffer overflow reading Id");
}
}
if (idLen > 4096000) {
return ValidationResult.error("Categories exceeds max length 4096000");
}
if ((nullBits & 2) != 0) {
int categoriesOffset = buffer.getIntLE(offset + 10);
if (categoriesOffset < 0) {
return ValidationResult.error("Invalid offset for Categories");
}
pos += VarInt.length(buffer, pos);
int posx = offset + 14 + categoriesOffset;
if (posx >= buffer.writerIndex()) {
return ValidationResult.error("Offset out of bounds for Categories");
}
for (int i = 0; i < idLen; i++) {
int strLen = VarInt.peek(buffer, pos);
if (strLen < 0) {
return ValidationResult.error("Invalid string length in Categories");
}
int categoriesCount = VarInt.peek(buffer, posx);
if (categoriesCount < 0) {
return ValidationResult.error("Invalid array count for Categories");
}
pos += VarInt.length(buffer, pos);
pos += strLen;
if (pos > buffer.writerIndex()) {
return ValidationResult.error("Buffer overflow reading string in Categories");
}
}
}
if (categoriesCount > 4096000) {
return ValidationResult.error("Categories exceeds max length 4096000");
}
posx += VarInt.length(buffer, posx);
for (int i = 0; i < categoriesCount; i++) {
int strLen = VarInt.peek(buffer, posx);
if (strLen < 0) {
return ValidationResult.error("Invalid string length in Categories");
}
posx += VarInt.length(buffer, posx);
posx += strLen;
if (posx > buffer.writerIndex()) {
return ValidationResult.error("Buffer overflow reading string in Categories");
return ValidationResult.OK;
}
}
}
}
return ValidationResult.OK;
}
}

View File

@@ -0,0 +1,79 @@
package com.hypixel.hytale.protocol;
import com.hypixel.hytale.protocol.io.ValidationResult;
import io.netty.buffer.ByteBuf;
import java.util.Objects;
import javax.annotation.Nonnull;
public class BlockUpdate extends ComponentUpdate {
public static final int NULLABLE_BIT_FIELD_SIZE = 0;
public static final int FIXED_BLOCK_SIZE = 8;
public static final int VARIABLE_FIELD_COUNT = 0;
public static final int VARIABLE_BLOCK_START = 8;
public static final int MAX_SIZE = 8;
public int blockId;
public float entityScale;
public BlockUpdate() {
}
public BlockUpdate(int blockId, float entityScale) {
this.blockId = blockId;
this.entityScale = entityScale;
}
public BlockUpdate(@Nonnull BlockUpdate other) {
this.blockId = other.blockId;
this.entityScale = other.entityScale;
}
@Nonnull
public static BlockUpdate deserialize(@Nonnull ByteBuf buf, int offset) {
BlockUpdate obj = new BlockUpdate();
obj.blockId = buf.getIntLE(offset + 0);
obj.entityScale = buf.getFloatLE(offset + 4);
return obj;
}
public static int computeBytesConsumed(@Nonnull ByteBuf buf, int offset) {
return 8;
}
@Override
public int serialize(@Nonnull ByteBuf buf) {
int startPos = buf.writerIndex();
buf.writeIntLE(this.blockId);
buf.writeFloatLE(this.entityScale);
return buf.writerIndex() - startPos;
}
@Override
public int computeSize() {
return 8;
}
public static ValidationResult validateStructure(@Nonnull ByteBuf buffer, int offset) {
return buffer.readableBytes() - offset < 8 ? ValidationResult.error("Buffer too small: expected at least 8 bytes") : ValidationResult.OK;
}
public BlockUpdate clone() {
BlockUpdate copy = new BlockUpdate();
copy.blockId = this.blockId;
copy.entityScale = this.entityScale;
return copy;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
} else {
return !(obj instanceof BlockUpdate other) ? false : this.blockId == other.blockId && this.entityScale == other.entityScale;
}
}
@Override
public int hashCode() {
return Objects.hash(this.blockId, this.entityScale);
}
}

View File

@@ -4,24 +4,26 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import javax.annotation.Nonnull;
public final class CachedPacket<T extends Packet> implements Packet, AutoCloseable {
public final class CachedPacket<T extends ToClientPacket> implements ToClientPacket, AutoCloseable {
private final Class<T> packetType;
private final int packetId;
private final NetworkChannel packetChannel;
private final ByteBuf cachedBytes;
private CachedPacket(Class<T> packetType, int packetId, ByteBuf cachedBytes) {
private CachedPacket(Class<T> packetType, int packetId, NetworkChannel packetChannel, ByteBuf cachedBytes) {
this.packetType = packetType;
this.packetId = packetId;
this.packetChannel = packetChannel;
this.cachedBytes = cachedBytes;
}
public static <T extends Packet> CachedPacket<T> cache(@Nonnull T packet) {
public static <T extends ToClientPacket> CachedPacket<T> cache(@Nonnull T packet) {
if (packet instanceof CachedPacket) {
throw new IllegalArgumentException("Cannot cache a CachedPacket");
} else {
ByteBuf buf = Unpooled.buffer();
packet.serialize(buf);
return new CachedPacket<>((Class<T>)packet.getClass(), packet.getId(), buf);
return new CachedPacket<>((Class<T>)packet.getClass(), packet.getId(), packet.getChannel(), buf);
}
}
@@ -30,6 +32,11 @@ public final class CachedPacket<T extends Packet> implements Packet, AutoCloseab
return this.packetId;
}
@Override
public NetworkChannel getChannel() {
return this.packetChannel;
}
@Override
public void serialize(@Nonnull ByteBuf buf) {
if (this.cachedBytes.refCnt() <= 0) {

View File

@@ -7,22 +7,21 @@ import com.hypixel.hytale.protocol.io.VarInt;
import io.netty.buffer.ByteBuf;
import java.util.Objects;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class CombatTextUpdate {
public static final int NULLABLE_BIT_FIELD_SIZE = 1;
public static final int FIXED_BLOCK_SIZE = 5;
public class CombatTextUpdate extends ComponentUpdate {
public static final int NULLABLE_BIT_FIELD_SIZE = 0;
public static final int FIXED_BLOCK_SIZE = 4;
public static final int VARIABLE_FIELD_COUNT = 1;
public static final int VARIABLE_BLOCK_START = 5;
public static final int MAX_SIZE = 16384010;
public static final int VARIABLE_BLOCK_START = 4;
public static final int MAX_SIZE = 16384009;
public float hitAngleDeg;
@Nullable
public String text;
@Nonnull
public String text = "";
public CombatTextUpdate() {
}
public CombatTextUpdate(float hitAngleDeg, @Nullable String text) {
public CombatTextUpdate(float hitAngleDeg, @Nonnull String text) {
this.hitAngleDeg = hitAngleDeg;
this.text = text;
}
@@ -35,84 +34,57 @@ public class CombatTextUpdate {
@Nonnull
public static CombatTextUpdate deserialize(@Nonnull ByteBuf buf, int offset) {
CombatTextUpdate obj = new CombatTextUpdate();
byte nullBits = buf.getByte(offset);
obj.hitAngleDeg = buf.getFloatLE(offset + 1);
int pos = offset + 5;
if ((nullBits & 1) != 0) {
int textLen = VarInt.peek(buf, pos);
if (textLen < 0) {
throw ProtocolException.negativeLength("Text", textLen);
}
if (textLen > 4096000) {
throw ProtocolException.stringTooLong("Text", textLen, 4096000);
}
obj.hitAngleDeg = buf.getFloatLE(offset + 0);
int pos = offset + 4;
int textLen = VarInt.peek(buf, pos);
if (textLen < 0) {
throw ProtocolException.negativeLength("Text", textLen);
} else if (textLen > 4096000) {
throw ProtocolException.stringTooLong("Text", textLen, 4096000);
} else {
int textVarLen = VarInt.length(buf, pos);
obj.text = PacketIO.readVarString(buf, pos, PacketIO.UTF8);
pos += textVarLen + textLen;
return obj;
}
return obj;
}
public static int computeBytesConsumed(@Nonnull ByteBuf buf, int offset) {
byte nullBits = buf.getByte(offset);
int pos = offset + 5;
if ((nullBits & 1) != 0) {
int sl = VarInt.peek(buf, pos);
pos += VarInt.length(buf, pos) + sl;
}
int pos = offset + 4;
int sl = VarInt.peek(buf, pos);
pos += VarInt.length(buf, pos) + sl;
return pos - offset;
}
public void serialize(@Nonnull ByteBuf buf) {
byte nullBits = 0;
if (this.text != null) {
nullBits = (byte)(nullBits | 1);
}
buf.writeByte(nullBits);
@Override
public int serialize(@Nonnull ByteBuf buf) {
int startPos = buf.writerIndex();
buf.writeFloatLE(this.hitAngleDeg);
if (this.text != null) {
PacketIO.writeVarString(buf, this.text, 4096000);
}
PacketIO.writeVarString(buf, this.text, 4096000);
return buf.writerIndex() - startPos;
}
@Override
public int computeSize() {
int size = 5;
if (this.text != null) {
size += PacketIO.stringSize(this.text);
}
return size;
int size = 4;
return size + PacketIO.stringSize(this.text);
}
public static ValidationResult validateStructure(@Nonnull ByteBuf buffer, int offset) {
if (buffer.readableBytes() - offset < 5) {
return ValidationResult.error("Buffer too small: expected at least 5 bytes");
if (buffer.readableBytes() - offset < 4) {
return ValidationResult.error("Buffer too small: expected at least 4 bytes");
} else {
byte nullBits = buffer.getByte(offset);
int pos = offset + 5;
if ((nullBits & 1) != 0) {
int textLen = VarInt.peek(buffer, pos);
if (textLen < 0) {
return ValidationResult.error("Invalid string length for Text");
}
if (textLen > 4096000) {
return ValidationResult.error("Text exceeds max length 4096000");
}
int pos = offset + 4;
int textLen = VarInt.peek(buffer, pos);
if (textLen < 0) {
return ValidationResult.error("Invalid string length for Text");
} else if (textLen > 4096000) {
return ValidationResult.error("Text exceeds max length 4096000");
} else {
pos += VarInt.length(buffer, pos);
pos += textLen;
if (pos > buffer.writerIndex()) {
return ValidationResult.error("Buffer overflow reading Text");
}
return pos > buffer.writerIndex() ? ValidationResult.error("Buffer overflow reading Text") : ValidationResult.OK;
}
return ValidationResult.OK;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,74 @@
package com.hypixel.hytale.protocol;
import com.hypixel.hytale.protocol.io.ValidationResult;
import io.netty.buffer.ByteBuf;
import java.util.Objects;
import javax.annotation.Nonnull;
public class DynamicLightUpdate extends ComponentUpdate {
public static final int NULLABLE_BIT_FIELD_SIZE = 0;
public static final int FIXED_BLOCK_SIZE = 4;
public static final int VARIABLE_FIELD_COUNT = 0;
public static final int VARIABLE_BLOCK_START = 4;
public static final int MAX_SIZE = 4;
@Nonnull
public ColorLight dynamicLight = new ColorLight();
public DynamicLightUpdate() {
}
public DynamicLightUpdate(@Nonnull ColorLight dynamicLight) {
this.dynamicLight = dynamicLight;
}
public DynamicLightUpdate(@Nonnull DynamicLightUpdate other) {
this.dynamicLight = other.dynamicLight;
}
@Nonnull
public static DynamicLightUpdate deserialize(@Nonnull ByteBuf buf, int offset) {
DynamicLightUpdate obj = new DynamicLightUpdate();
obj.dynamicLight = ColorLight.deserialize(buf, offset + 0);
return obj;
}
public static int computeBytesConsumed(@Nonnull ByteBuf buf, int offset) {
return 4;
}
@Override
public int serialize(@Nonnull ByteBuf buf) {
int startPos = buf.writerIndex();
this.dynamicLight.serialize(buf);
return buf.writerIndex() - startPos;
}
@Override
public int computeSize() {
return 4;
}
public static ValidationResult validateStructure(@Nonnull ByteBuf buffer, int offset) {
return buffer.readableBytes() - offset < 4 ? ValidationResult.error("Buffer too small: expected at least 4 bytes") : ValidationResult.OK;
}
public DynamicLightUpdate clone() {
DynamicLightUpdate copy = new DynamicLightUpdate();
copy.dynamicLight = this.dynamicLight.clone();
return copy;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
} else {
return obj instanceof DynamicLightUpdate other ? Objects.equals(this.dynamicLight, other.dynamicLight) : false;
}
}
@Override
public int hashCode() {
return Objects.hash(this.dynamicLight);
}
}

View File

@@ -0,0 +1,144 @@
package com.hypixel.hytale.protocol;
import com.hypixel.hytale.protocol.io.ProtocolException;
import com.hypixel.hytale.protocol.io.ValidationResult;
import com.hypixel.hytale.protocol.io.VarInt;
import io.netty.buffer.ByteBuf;
import java.util.Arrays;
import javax.annotation.Nonnull;
public class EntityEffectsUpdate extends ComponentUpdate {
public static final int NULLABLE_BIT_FIELD_SIZE = 0;
public static final int FIXED_BLOCK_SIZE = 0;
public static final int VARIABLE_FIELD_COUNT = 1;
public static final int VARIABLE_BLOCK_START = 0;
public static final int MAX_SIZE = 1677721600;
@Nonnull
public EntityEffectUpdate[] entityEffectUpdates = new EntityEffectUpdate[0];
public EntityEffectsUpdate() {
}
public EntityEffectsUpdate(@Nonnull EntityEffectUpdate[] entityEffectUpdates) {
this.entityEffectUpdates = entityEffectUpdates;
}
public EntityEffectsUpdate(@Nonnull EntityEffectsUpdate other) {
this.entityEffectUpdates = other.entityEffectUpdates;
}
@Nonnull
public static EntityEffectsUpdate deserialize(@Nonnull ByteBuf buf, int offset) {
EntityEffectsUpdate obj = new EntityEffectsUpdate();
int pos = offset + 0;
int entityEffectUpdatesCount = VarInt.peek(buf, pos);
if (entityEffectUpdatesCount < 0) {
throw ProtocolException.negativeLength("EntityEffectUpdates", entityEffectUpdatesCount);
} else if (entityEffectUpdatesCount > 4096000) {
throw ProtocolException.arrayTooLong("EntityEffectUpdates", entityEffectUpdatesCount, 4096000);
} else {
int entityEffectUpdatesVarLen = VarInt.size(entityEffectUpdatesCount);
if (pos + entityEffectUpdatesVarLen + entityEffectUpdatesCount * 12L > buf.readableBytes()) {
throw ProtocolException.bufferTooSmall("EntityEffectUpdates", pos + entityEffectUpdatesVarLen + entityEffectUpdatesCount * 12, buf.readableBytes());
} else {
pos += entityEffectUpdatesVarLen;
obj.entityEffectUpdates = new EntityEffectUpdate[entityEffectUpdatesCount];
for (int i = 0; i < entityEffectUpdatesCount; i++) {
obj.entityEffectUpdates[i] = EntityEffectUpdate.deserialize(buf, pos);
pos += EntityEffectUpdate.computeBytesConsumed(buf, pos);
}
return obj;
}
}
}
public static int computeBytesConsumed(@Nonnull ByteBuf buf, int offset) {
int pos = offset + 0;
int arrLen = VarInt.peek(buf, pos);
pos += VarInt.length(buf, pos);
for (int i = 0; i < arrLen; i++) {
pos += EntityEffectUpdate.computeBytesConsumed(buf, pos);
}
return pos - offset;
}
@Override
public int serialize(@Nonnull ByteBuf buf) {
int startPos = buf.writerIndex();
if (this.entityEffectUpdates.length > 4096000) {
throw ProtocolException.arrayTooLong("EntityEffectUpdates", this.entityEffectUpdates.length, 4096000);
} else {
VarInt.write(buf, this.entityEffectUpdates.length);
for (EntityEffectUpdate item : this.entityEffectUpdates) {
item.serialize(buf);
}
return buf.writerIndex() - startPos;
}
}
@Override
public int computeSize() {
int size = 0;
int entityEffectUpdatesSize = 0;
for (EntityEffectUpdate elem : this.entityEffectUpdates) {
entityEffectUpdatesSize += elem.computeSize();
}
return size + VarInt.size(this.entityEffectUpdates.length) + entityEffectUpdatesSize;
}
public static ValidationResult validateStructure(@Nonnull ByteBuf buffer, int offset) {
if (buffer.readableBytes() - offset < 0) {
return ValidationResult.error("Buffer too small: expected at least 0 bytes");
} else {
int pos = offset + 0;
int entityEffectUpdatesCount = VarInt.peek(buffer, pos);
if (entityEffectUpdatesCount < 0) {
return ValidationResult.error("Invalid array count for EntityEffectUpdates");
} else if (entityEffectUpdatesCount > 4096000) {
return ValidationResult.error("EntityEffectUpdates exceeds max length 4096000");
} else {
pos += VarInt.length(buffer, pos);
for (int i = 0; i < entityEffectUpdatesCount; i++) {
ValidationResult structResult = EntityEffectUpdate.validateStructure(buffer, pos);
if (!structResult.isValid()) {
return ValidationResult.error("Invalid EntityEffectUpdate in EntityEffectUpdates[" + i + "]: " + structResult.error());
}
pos += EntityEffectUpdate.computeBytesConsumed(buffer, pos);
}
return ValidationResult.OK;
}
}
}
public EntityEffectsUpdate clone() {
EntityEffectsUpdate copy = new EntityEffectsUpdate();
copy.entityEffectUpdates = Arrays.stream(this.entityEffectUpdates).map(e -> e.clone()).toArray(EntityEffectUpdate[]::new);
return copy;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
} else {
return obj instanceof EntityEffectsUpdate other ? Arrays.equals((Object[])this.entityEffectUpdates, (Object[])other.entityEffectUpdates) : false;
}
}
@Override
public int hashCode() {
int result = 1;
return 31 * result + Arrays.hashCode((Object[])this.entityEffectUpdates);
}
}

View File

@@ -0,0 +1,193 @@
package com.hypixel.hytale.protocol;
import com.hypixel.hytale.protocol.io.ProtocolException;
import com.hypixel.hytale.protocol.io.ValidationResult;
import com.hypixel.hytale.protocol.io.VarInt;
import io.netty.buffer.ByteBuf;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Map.Entry;
import javax.annotation.Nonnull;
public class EntityStatsUpdate extends ComponentUpdate {
public static final int NULLABLE_BIT_FIELD_SIZE = 0;
public static final int FIXED_BLOCK_SIZE = 0;
public static final int VARIABLE_FIELD_COUNT = 1;
public static final int VARIABLE_BLOCK_START = 0;
public static final int MAX_SIZE = 1677721600;
@Nonnull
public Map<Integer, EntityStatUpdate[]> entityStatUpdates = new HashMap<>();
public EntityStatsUpdate() {
}
public EntityStatsUpdate(@Nonnull Map<Integer, EntityStatUpdate[]> entityStatUpdates) {
this.entityStatUpdates = entityStatUpdates;
}
public EntityStatsUpdate(@Nonnull EntityStatsUpdate other) {
this.entityStatUpdates = other.entityStatUpdates;
}
@Nonnull
public static EntityStatsUpdate deserialize(@Nonnull ByteBuf buf, int offset) {
EntityStatsUpdate obj = new EntityStatsUpdate();
int pos = offset + 0;
int entityStatUpdatesCount = VarInt.peek(buf, pos);
if (entityStatUpdatesCount < 0) {
throw ProtocolException.negativeLength("EntityStatUpdates", entityStatUpdatesCount);
} else if (entityStatUpdatesCount > 4096000) {
throw ProtocolException.dictionaryTooLarge("EntityStatUpdates", entityStatUpdatesCount, 4096000);
} else {
pos += VarInt.size(entityStatUpdatesCount);
obj.entityStatUpdates = new HashMap<>(entityStatUpdatesCount);
for (int i = 0; i < entityStatUpdatesCount; i++) {
int key = buf.getIntLE(pos);
pos += 4;
int valLen = VarInt.peek(buf, pos);
if (valLen < 0) {
throw ProtocolException.negativeLength("val", valLen);
}
if (valLen > 64) {
throw ProtocolException.arrayTooLong("val", valLen, 64);
}
int valVarLen = VarInt.length(buf, pos);
if (pos + valVarLen + valLen * 13L > buf.readableBytes()) {
throw ProtocolException.bufferTooSmall("val", pos + valVarLen + valLen * 13, buf.readableBytes());
}
pos += valVarLen;
EntityStatUpdate[] val = new EntityStatUpdate[valLen];
for (int valIdx = 0; valIdx < valLen; valIdx++) {
val[valIdx] = EntityStatUpdate.deserialize(buf, pos);
pos += EntityStatUpdate.computeBytesConsumed(buf, pos);
}
if (obj.entityStatUpdates.put(key, val) != null) {
throw ProtocolException.duplicateKey("entityStatUpdates", key);
}
}
return obj;
}
}
public static int computeBytesConsumed(@Nonnull ByteBuf buf, int offset) {
int pos = offset + 0;
int dictLen = VarInt.peek(buf, pos);
pos += VarInt.length(buf, pos);
for (int i = 0; i < dictLen; i++) {
pos += 4;
int al = VarInt.peek(buf, pos);
pos += VarInt.length(buf, pos);
for (int j = 0; j < al; j++) {
pos += EntityStatUpdate.computeBytesConsumed(buf, pos);
}
}
return pos - offset;
}
@Override
public int serialize(@Nonnull ByteBuf buf) {
int startPos = buf.writerIndex();
if (this.entityStatUpdates.size() > 4096000) {
throw ProtocolException.dictionaryTooLarge("EntityStatUpdates", this.entityStatUpdates.size(), 4096000);
} else {
VarInt.write(buf, this.entityStatUpdates.size());
for (Entry<Integer, EntityStatUpdate[]> e : this.entityStatUpdates.entrySet()) {
buf.writeIntLE(e.getKey());
VarInt.write(buf, e.getValue().length);
for (EntityStatUpdate arrItem : e.getValue()) {
arrItem.serialize(buf);
}
}
return buf.writerIndex() - startPos;
}
}
@Override
public int computeSize() {
int size = 0;
int entityStatUpdatesSize = 0;
for (Entry<Integer, EntityStatUpdate[]> kvp : this.entityStatUpdates.entrySet()) {
entityStatUpdatesSize += 4 + VarInt.size(kvp.getValue().length) + Arrays.stream(kvp.getValue()).mapToInt(inner -> inner.computeSize()).sum();
}
return size + VarInt.size(this.entityStatUpdates.size()) + entityStatUpdatesSize;
}
public static ValidationResult validateStructure(@Nonnull ByteBuf buffer, int offset) {
if (buffer.readableBytes() - offset < 0) {
return ValidationResult.error("Buffer too small: expected at least 0 bytes");
} else {
int pos = offset + 0;
int entityStatUpdatesCount = VarInt.peek(buffer, pos);
if (entityStatUpdatesCount < 0) {
return ValidationResult.error("Invalid dictionary count for EntityStatUpdates");
} else if (entityStatUpdatesCount > 4096000) {
return ValidationResult.error("EntityStatUpdates exceeds max length 4096000");
} else {
pos += VarInt.length(buffer, pos);
for (int i = 0; i < entityStatUpdatesCount; i++) {
pos += 4;
if (pos > buffer.writerIndex()) {
return ValidationResult.error("Buffer overflow reading key");
}
int valueArrCount = VarInt.peek(buffer, pos);
if (valueArrCount < 0) {
return ValidationResult.error("Invalid array count for value");
}
pos += VarInt.length(buffer, pos);
for (int valueArrIdx = 0; valueArrIdx < valueArrCount; valueArrIdx++) {
pos += EntityStatUpdate.computeBytesConsumed(buffer, pos);
}
}
return ValidationResult.OK;
}
}
}
public EntityStatsUpdate clone() {
EntityStatsUpdate copy = new EntityStatsUpdate();
Map<Integer, EntityStatUpdate[]> m = new HashMap<>();
for (Entry<Integer, EntityStatUpdate[]> e : this.entityStatUpdates.entrySet()) {
m.put(e.getKey(), Arrays.stream(e.getValue()).map(x -> x.clone()).toArray(EntityStatUpdate[]::new));
}
copy.entityStatUpdates = m;
return copy;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
} else {
return obj instanceof EntityStatsUpdate other ? Objects.equals(this.entityStatUpdates, other.entityStatUpdates) : false;
}
}
@Override
public int hashCode() {
return Objects.hash(this.entityStatUpdates);
}
}

View File

@@ -77,8 +77,8 @@ public class EntityUpdate {
}
int varIntLen = VarInt.length(buf, varPos1);
if (varPos1 + varIntLen + updatesCount * 160L > buf.readableBytes()) {
throw ProtocolException.bufferTooSmall("Updates", varPos1 + varIntLen + updatesCount * 160, buf.readableBytes());
if (varPos1 + varIntLen + updatesCount * 1L > buf.readableBytes()) {
throw ProtocolException.bufferTooSmall("Updates", varPos1 + varIntLen + updatesCount * 1, buf.readableBytes());
}
obj.updates = new ComponentUpdate[updatesCount];
@@ -166,7 +166,7 @@ public class EntityUpdate {
VarInt.write(buf, this.updates.length);
for (ComponentUpdate item : this.updates) {
item.serialize(buf);
item.serializeWithTypeId(buf);
}
} else {
buf.setIntLE(updatesOffsetSlot, -1);
@@ -183,7 +183,7 @@ public class EntityUpdate {
int updatesSize = 0;
for (ComponentUpdate elem : this.updates) {
updatesSize += elem.computeSize();
updatesSize += elem.computeSizeWithTypeId();
}
size += VarInt.size(this.updates.length) + updatesSize;
@@ -264,7 +264,7 @@ public class EntityUpdate {
EntityUpdate copy = new EntityUpdate();
copy.networkId = this.networkId;
copy.removed = this.removed != null ? Arrays.copyOf(this.removed, this.removed.length) : null;
copy.updates = this.updates != null ? Arrays.stream(this.updates).map(e -> e.clone()).toArray(ComponentUpdate[]::new) : null;
copy.updates = this.updates != null ? Arrays.copyOf(this.updates, this.updates.length) : null;
return copy;
}

View File

@@ -10,7 +10,7 @@ import java.util.Objects;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class Equipment {
public class EquipmentUpdate extends ComponentUpdate {
public static final int NULLABLE_BIT_FIELD_SIZE = 1;
public static final int FIXED_BLOCK_SIZE = 1;
public static final int VARIABLE_FIELD_COUNT = 3;
@@ -23,24 +23,24 @@ public class Equipment {
@Nullable
public String leftHandItemId;
public Equipment() {
public EquipmentUpdate() {
}
public Equipment(@Nullable String[] armorIds, @Nullable String rightHandItemId, @Nullable String leftHandItemId) {
public EquipmentUpdate(@Nullable String[] armorIds, @Nullable String rightHandItemId, @Nullable String leftHandItemId) {
this.armorIds = armorIds;
this.rightHandItemId = rightHandItemId;
this.leftHandItemId = leftHandItemId;
}
public Equipment(@Nonnull Equipment other) {
public EquipmentUpdate(@Nonnull EquipmentUpdate other) {
this.armorIds = other.armorIds;
this.rightHandItemId = other.rightHandItemId;
this.leftHandItemId = other.leftHandItemId;
}
@Nonnull
public static Equipment deserialize(@Nonnull ByteBuf buf, int offset) {
Equipment obj = new Equipment();
public static EquipmentUpdate deserialize(@Nonnull ByteBuf buf, int offset) {
EquipmentUpdate obj = new EquipmentUpdate();
byte nullBits = buf.getByte(offset);
if ((nullBits & 1) != 0) {
int varPos0 = offset + 13 + buf.getIntLE(offset + 1);
@@ -150,7 +150,8 @@ public class Equipment {
return maxEnd;
}
public void serialize(@Nonnull ByteBuf buf) {
@Override
public int serialize(@Nonnull ByteBuf buf) {
int startPos = buf.writerIndex();
byte nullBits = 0;
if (this.armorIds != null) {
@@ -201,8 +202,11 @@ public class Equipment {
} else {
buf.setIntLE(leftHandItemIdOffsetSlot, -1);
}
return buf.writerIndex() - startPos;
}
@Override
public int computeSize() {
int size = 13;
if (this.armorIds != null) {
@@ -325,8 +329,8 @@ public class Equipment {
}
}
public Equipment clone() {
Equipment copy = new Equipment();
public EquipmentUpdate clone() {
EquipmentUpdate copy = new EquipmentUpdate();
copy.armorIds = this.armorIds != null ? Arrays.copyOf(this.armorIds, this.armorIds.length) : null;
copy.rightHandItemId = this.rightHandItemId;
copy.leftHandItemId = this.leftHandItemId;
@@ -338,7 +342,7 @@ public class Equipment {
if (this == obj) {
return true;
} else {
return !(obj instanceof Equipment other)
return !(obj instanceof EquipmentUpdate other)
? false
: Arrays.equals((Object[])this.armorIds, (Object[])other.armorIds)
&& Objects.equals(this.rightHandItemId, other.rightHandItemId)

View File

@@ -0,0 +1,73 @@
package com.hypixel.hytale.protocol;
import com.hypixel.hytale.protocol.io.ValidationResult;
import io.netty.buffer.ByteBuf;
import java.util.Objects;
import javax.annotation.Nonnull;
public class HitboxCollisionUpdate extends ComponentUpdate {
public static final int NULLABLE_BIT_FIELD_SIZE = 0;
public static final int FIXED_BLOCK_SIZE = 4;
public static final int VARIABLE_FIELD_COUNT = 0;
public static final int VARIABLE_BLOCK_START = 4;
public static final int MAX_SIZE = 4;
public int hitboxCollisionConfigIndex;
public HitboxCollisionUpdate() {
}
public HitboxCollisionUpdate(int hitboxCollisionConfigIndex) {
this.hitboxCollisionConfigIndex = hitboxCollisionConfigIndex;
}
public HitboxCollisionUpdate(@Nonnull HitboxCollisionUpdate other) {
this.hitboxCollisionConfigIndex = other.hitboxCollisionConfigIndex;
}
@Nonnull
public static HitboxCollisionUpdate deserialize(@Nonnull ByteBuf buf, int offset) {
HitboxCollisionUpdate obj = new HitboxCollisionUpdate();
obj.hitboxCollisionConfigIndex = buf.getIntLE(offset + 0);
return obj;
}
public static int computeBytesConsumed(@Nonnull ByteBuf buf, int offset) {
return 4;
}
@Override
public int serialize(@Nonnull ByteBuf buf) {
int startPos = buf.writerIndex();
buf.writeIntLE(this.hitboxCollisionConfigIndex);
return buf.writerIndex() - startPos;
}
@Override
public int computeSize() {
return 4;
}
public static ValidationResult validateStructure(@Nonnull ByteBuf buffer, int offset) {
return buffer.readableBytes() - offset < 4 ? ValidationResult.error("Buffer too small: expected at least 4 bytes") : ValidationResult.OK;
}
public HitboxCollisionUpdate clone() {
HitboxCollisionUpdate copy = new HitboxCollisionUpdate();
copy.hitboxCollisionConfigIndex = this.hitboxCollisionConfigIndex;
return copy;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
} else {
return obj instanceof HitboxCollisionUpdate other ? this.hitboxCollisionConfigIndex == other.hitboxCollisionConfigIndex : false;
}
}
@Override
public int hashCode() {
return Objects.hash(this.hitboxCollisionConfigIndex);
}
}

View File

@@ -0,0 +1,51 @@
package com.hypixel.hytale.protocol;
import com.hypixel.hytale.protocol.io.ValidationResult;
import io.netty.buffer.ByteBuf;
import javax.annotation.Nonnull;
public class IntangibleUpdate extends ComponentUpdate {
public static final int NULLABLE_BIT_FIELD_SIZE = 0;
public static final int FIXED_BLOCK_SIZE = 0;
public static final int VARIABLE_FIELD_COUNT = 0;
public static final int VARIABLE_BLOCK_START = 0;
public static final int MAX_SIZE = 0;
@Nonnull
public static IntangibleUpdate deserialize(@Nonnull ByteBuf buf, int offset) {
return new IntangibleUpdate();
}
public static int computeBytesConsumed(@Nonnull ByteBuf buf, int offset) {
return 0;
}
@Override
public int serialize(@Nonnull ByteBuf buf) {
int startPos = buf.writerIndex();
return buf.writerIndex() - startPos;
}
@Override
public int computeSize() {
return 0;
}
public static ValidationResult validateStructure(@Nonnull ByteBuf buffer, int offset) {
return buffer.readableBytes() - offset < 0 ? ValidationResult.error("Buffer too small: expected at least 0 bytes") : ValidationResult.OK;
}
public IntangibleUpdate clone() {
return new IntangibleUpdate();
}
@Override
public boolean equals(Object obj) {
return this == obj ? true : obj instanceof IntangibleUpdate other;
}
@Override
public int hashCode() {
return 0;
}
}

View File

@@ -9,44 +9,44 @@ import java.util.Objects;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class Nameplate {
public class InteractableUpdate extends ComponentUpdate {
public static final int NULLABLE_BIT_FIELD_SIZE = 1;
public static final int FIXED_BLOCK_SIZE = 1;
public static final int VARIABLE_FIELD_COUNT = 1;
public static final int VARIABLE_BLOCK_START = 1;
public static final int MAX_SIZE = 16384006;
@Nullable
public String text;
public String interactionHint;
public Nameplate() {
public InteractableUpdate() {
}
public Nameplate(@Nullable String text) {
this.text = text;
public InteractableUpdate(@Nullable String interactionHint) {
this.interactionHint = interactionHint;
}
public Nameplate(@Nonnull Nameplate other) {
this.text = other.text;
public InteractableUpdate(@Nonnull InteractableUpdate other) {
this.interactionHint = other.interactionHint;
}
@Nonnull
public static Nameplate deserialize(@Nonnull ByteBuf buf, int offset) {
Nameplate obj = new Nameplate();
public static InteractableUpdate deserialize(@Nonnull ByteBuf buf, int offset) {
InteractableUpdate obj = new InteractableUpdate();
byte nullBits = buf.getByte(offset);
int pos = offset + 1;
if ((nullBits & 1) != 0) {
int textLen = VarInt.peek(buf, pos);
if (textLen < 0) {
throw ProtocolException.negativeLength("Text", textLen);
int interactionHintLen = VarInt.peek(buf, pos);
if (interactionHintLen < 0) {
throw ProtocolException.negativeLength("InteractionHint", interactionHintLen);
}
if (textLen > 4096000) {
throw ProtocolException.stringTooLong("Text", textLen, 4096000);
if (interactionHintLen > 4096000) {
throw ProtocolException.stringTooLong("InteractionHint", interactionHintLen, 4096000);
}
int textVarLen = VarInt.length(buf, pos);
obj.text = PacketIO.readVarString(buf, pos, PacketIO.UTF8);
pos += textVarLen + textLen;
int interactionHintVarLen = VarInt.length(buf, pos);
obj.interactionHint = PacketIO.readVarString(buf, pos, PacketIO.UTF8);
pos += interactionHintVarLen + interactionHintLen;
}
return obj;
@@ -63,22 +63,27 @@ public class Nameplate {
return pos - offset;
}
public void serialize(@Nonnull ByteBuf buf) {
@Override
public int serialize(@Nonnull ByteBuf buf) {
int startPos = buf.writerIndex();
byte nullBits = 0;
if (this.text != null) {
if (this.interactionHint != null) {
nullBits = (byte)(nullBits | 1);
}
buf.writeByte(nullBits);
if (this.text != null) {
PacketIO.writeVarString(buf, this.text, 4096000);
if (this.interactionHint != null) {
PacketIO.writeVarString(buf, this.interactionHint, 4096000);
}
return buf.writerIndex() - startPos;
}
@Override
public int computeSize() {
int size = 1;
if (this.text != null) {
size += PacketIO.stringSize(this.text);
if (this.interactionHint != null) {
size += PacketIO.stringSize(this.interactionHint);
}
return size;
@@ -91,19 +96,19 @@ public class Nameplate {
byte nullBits = buffer.getByte(offset);
int pos = offset + 1;
if ((nullBits & 1) != 0) {
int textLen = VarInt.peek(buffer, pos);
if (textLen < 0) {
return ValidationResult.error("Invalid string length for Text");
int interactionHintLen = VarInt.peek(buffer, pos);
if (interactionHintLen < 0) {
return ValidationResult.error("Invalid string length for InteractionHint");
}
if (textLen > 4096000) {
return ValidationResult.error("Text exceeds max length 4096000");
if (interactionHintLen > 4096000) {
return ValidationResult.error("InteractionHint exceeds max length 4096000");
}
pos += VarInt.length(buffer, pos);
pos += textLen;
pos += interactionHintLen;
if (pos > buffer.writerIndex()) {
return ValidationResult.error("Buffer overflow reading Text");
return ValidationResult.error("Buffer overflow reading InteractionHint");
}
}
@@ -111,9 +116,9 @@ public class Nameplate {
}
}
public Nameplate clone() {
Nameplate copy = new Nameplate();
copy.text = this.text;
public InteractableUpdate clone() {
InteractableUpdate copy = new InteractableUpdate();
copy.interactionHint = this.interactionHint;
return copy;
}
@@ -122,12 +127,12 @@ public class Nameplate {
if (this == obj) {
return true;
} else {
return obj instanceof Nameplate other ? Objects.equals(this.text, other.text) : false;
return obj instanceof InteractableUpdate other ? Objects.equals(this.interactionHint, other.interactionHint) : false;
}
}
@Override
public int hashCode() {
return Objects.hash(this.text);
return Objects.hash(this.interactionHint);
}
}

View File

@@ -0,0 +1,241 @@
package com.hypixel.hytale.protocol;
import com.hypixel.hytale.protocol.io.PacketIO;
import com.hypixel.hytale.protocol.io.ProtocolException;
import com.hypixel.hytale.protocol.io.ValidationResult;
import com.hypixel.hytale.protocol.io.VarInt;
import io.netty.buffer.ByteBuf;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Map.Entry;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class InteractionsUpdate extends ComponentUpdate {
public static final int NULLABLE_BIT_FIELD_SIZE = 1;
public static final int FIXED_BLOCK_SIZE = 1;
public static final int VARIABLE_FIELD_COUNT = 2;
public static final int VARIABLE_BLOCK_START = 9;
public static final int MAX_SIZE = 36864019;
@Nonnull
public Map<InteractionType, Integer> interactions = new HashMap<>();
@Nullable
public String interactionHint;
public InteractionsUpdate() {
}
public InteractionsUpdate(@Nonnull Map<InteractionType, Integer> interactions, @Nullable String interactionHint) {
this.interactions = interactions;
this.interactionHint = interactionHint;
}
public InteractionsUpdate(@Nonnull InteractionsUpdate other) {
this.interactions = other.interactions;
this.interactionHint = other.interactionHint;
}
@Nonnull
public static InteractionsUpdate deserialize(@Nonnull ByteBuf buf, int offset) {
InteractionsUpdate obj = new InteractionsUpdate();
byte nullBits = buf.getByte(offset);
int varPos0 = offset + 9 + buf.getIntLE(offset + 1);
int interactionsCount = VarInt.peek(buf, varPos0);
if (interactionsCount < 0) {
throw ProtocolException.negativeLength("Interactions", interactionsCount);
} else if (interactionsCount > 4096000) {
throw ProtocolException.dictionaryTooLarge("Interactions", interactionsCount, 4096000);
} else {
int varIntLen = VarInt.length(buf, varPos0);
obj.interactions = new HashMap<>(interactionsCount);
int dictPos = varPos0 + varIntLen;
for (int i = 0; i < interactionsCount; i++) {
InteractionType key = InteractionType.fromValue(buf.getByte(dictPos));
int val = buf.getIntLE(++dictPos);
dictPos += 4;
if (obj.interactions.put(key, val) != null) {
throw ProtocolException.duplicateKey("interactions", key);
}
}
if ((nullBits & 1) != 0) {
varPos0 = offset + 9 + buf.getIntLE(offset + 5);
interactionsCount = VarInt.peek(buf, varPos0);
if (interactionsCount < 0) {
throw ProtocolException.negativeLength("InteractionHint", interactionsCount);
}
if (interactionsCount > 4096000) {
throw ProtocolException.stringTooLong("InteractionHint", interactionsCount, 4096000);
}
obj.interactionHint = PacketIO.readVarString(buf, varPos0, PacketIO.UTF8);
}
return obj;
}
}
public static int computeBytesConsumed(@Nonnull ByteBuf buf, int offset) {
byte nullBits = buf.getByte(offset);
int maxEnd = 9;
int fieldOffset0 = buf.getIntLE(offset + 1);
int pos0 = offset + 9 + fieldOffset0;
int dictLen = VarInt.peek(buf, pos0);
pos0 += VarInt.length(buf, pos0);
for (int i = 0; i < dictLen; i++) {
pos0 = ++pos0 + 4;
}
if (pos0 - offset > maxEnd) {
maxEnd = pos0 - offset;
}
if ((nullBits & 1) != 0) {
fieldOffset0 = buf.getIntLE(offset + 5);
pos0 = offset + 9 + fieldOffset0;
dictLen = VarInt.peek(buf, pos0);
pos0 += VarInt.length(buf, pos0) + dictLen;
if (pos0 - offset > maxEnd) {
maxEnd = pos0 - offset;
}
}
return maxEnd;
}
@Override
public int serialize(@Nonnull ByteBuf buf) {
int startPos = buf.writerIndex();
byte nullBits = 0;
if (this.interactionHint != null) {
nullBits = (byte)(nullBits | 1);
}
buf.writeByte(nullBits);
int interactionsOffsetSlot = buf.writerIndex();
buf.writeIntLE(0);
int interactionHintOffsetSlot = buf.writerIndex();
buf.writeIntLE(0);
int varBlockStart = buf.writerIndex();
buf.setIntLE(interactionsOffsetSlot, buf.writerIndex() - varBlockStart);
if (this.interactions.size() > 4096000) {
throw ProtocolException.dictionaryTooLarge("Interactions", this.interactions.size(), 4096000);
} else {
VarInt.write(buf, this.interactions.size());
for (Entry<InteractionType, Integer> e : this.interactions.entrySet()) {
buf.writeByte(e.getKey().getValue());
buf.writeIntLE(e.getValue());
}
if (this.interactionHint != null) {
buf.setIntLE(interactionHintOffsetSlot, buf.writerIndex() - varBlockStart);
PacketIO.writeVarString(buf, this.interactionHint, 4096000);
} else {
buf.setIntLE(interactionHintOffsetSlot, -1);
}
return buf.writerIndex() - startPos;
}
}
@Override
public int computeSize() {
int size = 9;
size += VarInt.size(this.interactions.size()) + this.interactions.size() * 5;
if (this.interactionHint != null) {
size += PacketIO.stringSize(this.interactionHint);
}
return size;
}
public static ValidationResult validateStructure(@Nonnull ByteBuf buffer, int offset) {
if (buffer.readableBytes() - offset < 9) {
return ValidationResult.error("Buffer too small: expected at least 9 bytes");
} else {
byte nullBits = buffer.getByte(offset);
int interactionsOffset = buffer.getIntLE(offset + 1);
if (interactionsOffset < 0) {
return ValidationResult.error("Invalid offset for Interactions");
} else {
int pos = offset + 9 + interactionsOffset;
if (pos >= buffer.writerIndex()) {
return ValidationResult.error("Offset out of bounds for Interactions");
} else {
int interactionsCount = VarInt.peek(buffer, pos);
if (interactionsCount < 0) {
return ValidationResult.error("Invalid dictionary count for Interactions");
} else if (interactionsCount > 4096000) {
return ValidationResult.error("Interactions exceeds max length 4096000");
} else {
pos += VarInt.length(buffer, pos);
for (int i = 0; i < interactionsCount; i++) {
pos = ++pos + 4;
if (pos > buffer.writerIndex()) {
return ValidationResult.error("Buffer overflow reading value");
}
}
if ((nullBits & 1) != 0) {
interactionsOffset = buffer.getIntLE(offset + 5);
if (interactionsOffset < 0) {
return ValidationResult.error("Invalid offset for InteractionHint");
}
pos = offset + 9 + interactionsOffset;
if (pos >= buffer.writerIndex()) {
return ValidationResult.error("Offset out of bounds for InteractionHint");
}
interactionsCount = VarInt.peek(buffer, pos);
if (interactionsCount < 0) {
return ValidationResult.error("Invalid string length for InteractionHint");
}
if (interactionsCount > 4096000) {
return ValidationResult.error("InteractionHint exceeds max length 4096000");
}
pos += VarInt.length(buffer, pos);
pos += interactionsCount;
if (pos > buffer.writerIndex()) {
return ValidationResult.error("Buffer overflow reading InteractionHint");
}
}
return ValidationResult.OK;
}
}
}
}
}
public InteractionsUpdate clone() {
InteractionsUpdate copy = new InteractionsUpdate();
copy.interactions = new HashMap<>(this.interactions);
copy.interactionHint = this.interactionHint;
return copy;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
} else {
return !(obj instanceof InteractionsUpdate other)
? false
: Objects.equals(this.interactions, other.interactions) && Objects.equals(this.interactionHint, other.interactionHint);
}
}
@Override
public int hashCode() {
return Objects.hash(this.interactions, this.interactionHint);
}
}

View File

@@ -0,0 +1,51 @@
package com.hypixel.hytale.protocol;
import com.hypixel.hytale.protocol.io.ValidationResult;
import io.netty.buffer.ByteBuf;
import javax.annotation.Nonnull;
public class InvulnerableUpdate extends ComponentUpdate {
public static final int NULLABLE_BIT_FIELD_SIZE = 0;
public static final int FIXED_BLOCK_SIZE = 0;
public static final int VARIABLE_FIELD_COUNT = 0;
public static final int VARIABLE_BLOCK_START = 0;
public static final int MAX_SIZE = 0;
@Nonnull
public static InvulnerableUpdate deserialize(@Nonnull ByteBuf buf, int offset) {
return new InvulnerableUpdate();
}
public static int computeBytesConsumed(@Nonnull ByteBuf buf, int offset) {
return 0;
}
@Override
public int serialize(@Nonnull ByteBuf buf) {
int startPos = buf.writerIndex();
return buf.writerIndex() - startPos;
}
@Override
public int computeSize() {
return 0;
}
public static ValidationResult validateStructure(@Nonnull ByteBuf buffer, int offset) {
return buffer.readableBytes() - offset < 0 ? ValidationResult.error("Buffer too small: expected at least 0 bytes") : ValidationResult.OK;
}
public InvulnerableUpdate clone() {
return new InvulnerableUpdate();
}
@Override
public boolean equals(Object obj) {
return this == obj ? true : obj instanceof InvulnerableUpdate other;
}
@Override
public int hashCode() {
return 0;
}
}

View File

@@ -0,0 +1,96 @@
package com.hypixel.hytale.protocol;
import com.hypixel.hytale.protocol.io.ValidationResult;
import io.netty.buffer.ByteBuf;
import java.util.Objects;
import javax.annotation.Nonnull;
public class ItemUpdate extends ComponentUpdate {
public static final int NULLABLE_BIT_FIELD_SIZE = 0;
public static final int FIXED_BLOCK_SIZE = 4;
public static final int VARIABLE_FIELD_COUNT = 1;
public static final int VARIABLE_BLOCK_START = 4;
public static final int MAX_SIZE = 32768044;
@Nonnull
public ItemWithAllMetadata item = new ItemWithAllMetadata();
public float entityScale;
public ItemUpdate() {
}
public ItemUpdate(@Nonnull ItemWithAllMetadata item, float entityScale) {
this.item = item;
this.entityScale = entityScale;
}
public ItemUpdate(@Nonnull ItemUpdate other) {
this.item = other.item;
this.entityScale = other.entityScale;
}
@Nonnull
public static ItemUpdate deserialize(@Nonnull ByteBuf buf, int offset) {
ItemUpdate obj = new ItemUpdate();
obj.entityScale = buf.getFloatLE(offset + 0);
int pos = offset + 4;
obj.item = ItemWithAllMetadata.deserialize(buf, pos);
pos += ItemWithAllMetadata.computeBytesConsumed(buf, pos);
return obj;
}
public static int computeBytesConsumed(@Nonnull ByteBuf buf, int offset) {
int pos = offset + 4;
pos += ItemWithAllMetadata.computeBytesConsumed(buf, pos);
return pos - offset;
}
@Override
public int serialize(@Nonnull ByteBuf buf) {
int startPos = buf.writerIndex();
buf.writeFloatLE(this.entityScale);
this.item.serialize(buf);
return buf.writerIndex() - startPos;
}
@Override
public int computeSize() {
int size = 4;
return size + this.item.computeSize();
}
public static ValidationResult validateStructure(@Nonnull ByteBuf buffer, int offset) {
if (buffer.readableBytes() - offset < 4) {
return ValidationResult.error("Buffer too small: expected at least 4 bytes");
} else {
int pos = offset + 4;
ValidationResult itemResult = ItemWithAllMetadata.validateStructure(buffer, pos);
if (!itemResult.isValid()) {
return ValidationResult.error("Invalid Item: " + itemResult.error());
} else {
pos += ItemWithAllMetadata.computeBytesConsumed(buffer, pos);
return ValidationResult.OK;
}
}
}
public ItemUpdate clone() {
ItemUpdate copy = new ItemUpdate();
copy.item = this.item.clone();
copy.entityScale = this.entityScale;
return copy;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
} else {
return !(obj instanceof ItemUpdate other) ? false : Objects.equals(this.item, other.item) && this.entityScale == other.entityScale;
}
}
@Override
public int hashCode() {
return Objects.hash(this.item, this.entityScale);
}
}

View File

@@ -15,9 +15,9 @@ import javax.annotation.Nullable;
public class Model {
public static final int NULLABLE_BIT_FIELD_SIZE = 2;
public static final int FIXED_BLOCK_SIZE = 43;
public static final int FIXED_BLOCK_SIZE = 51;
public static final int VARIABLE_FIELD_COUNT = 12;
public static final int VARIABLE_BLOCK_START = 91;
public static final int VARIABLE_BLOCK_START = 99;
public static final int MAX_SIZE = 1677721600;
@Nullable
public String assetId;
@@ -34,6 +34,8 @@ public class Model {
public float scale;
public float eyeHeight;
public float crouchOffset;
public float sittingOffset;
public float sleepingOffset;
@Nullable
public Map<String, AnimationSet> animationSets;
@Nullable
@@ -66,6 +68,8 @@ public class Model {
float scale,
float eyeHeight,
float crouchOffset,
float sittingOffset,
float sleepingOffset,
@Nullable Map<String, AnimationSet> animationSets,
@Nullable ModelAttachment[] attachments,
@Nullable Hitbox hitbox,
@@ -85,6 +89,8 @@ public class Model {
this.scale = scale;
this.eyeHeight = eyeHeight;
this.crouchOffset = crouchOffset;
this.sittingOffset = sittingOffset;
this.sleepingOffset = sleepingOffset;
this.animationSets = animationSets;
this.attachments = attachments;
this.hitbox = hitbox;
@@ -106,6 +112,8 @@ public class Model {
this.scale = other.scale;
this.eyeHeight = other.eyeHeight;
this.crouchOffset = other.crouchOffset;
this.sittingOffset = other.sittingOffset;
this.sleepingOffset = other.sleepingOffset;
this.animationSets = other.animationSets;
this.attachments = other.attachments;
this.hitbox = other.hitbox;
@@ -124,17 +132,19 @@ public class Model {
obj.scale = buf.getFloatLE(offset + 2);
obj.eyeHeight = buf.getFloatLE(offset + 6);
obj.crouchOffset = buf.getFloatLE(offset + 10);
obj.sittingOffset = buf.getFloatLE(offset + 14);
obj.sleepingOffset = buf.getFloatLE(offset + 18);
if ((nullBits[0] & 1) != 0) {
obj.hitbox = Hitbox.deserialize(buf, offset + 14);
obj.hitbox = Hitbox.deserialize(buf, offset + 22);
}
if ((nullBits[0] & 2) != 0) {
obj.light = ColorLight.deserialize(buf, offset + 38);
obj.light = ColorLight.deserialize(buf, offset + 46);
}
obj.phobia = Phobia.fromValue(buf.getByte(offset + 42));
obj.phobia = Phobia.fromValue(buf.getByte(offset + 50));
if ((nullBits[0] & 4) != 0) {
int varPos0 = offset + 91 + buf.getIntLE(offset + 43);
int varPos0 = offset + 99 + buf.getIntLE(offset + 51);
int assetIdLen = VarInt.peek(buf, varPos0);
if (assetIdLen < 0) {
throw ProtocolException.negativeLength("AssetId", assetIdLen);
@@ -148,7 +158,7 @@ public class Model {
}
if ((nullBits[0] & 8) != 0) {
int varPos1 = offset + 91 + buf.getIntLE(offset + 47);
int varPos1 = offset + 99 + buf.getIntLE(offset + 55);
int pathLen = VarInt.peek(buf, varPos1);
if (pathLen < 0) {
throw ProtocolException.negativeLength("Path", pathLen);
@@ -162,7 +172,7 @@ public class Model {
}
if ((nullBits[0] & 16) != 0) {
int varPos2 = offset + 91 + buf.getIntLE(offset + 51);
int varPos2 = offset + 99 + buf.getIntLE(offset + 59);
int textureLen = VarInt.peek(buf, varPos2);
if (textureLen < 0) {
throw ProtocolException.negativeLength("Texture", textureLen);
@@ -176,7 +186,7 @@ public class Model {
}
if ((nullBits[0] & 32) != 0) {
int varPos3 = offset + 91 + buf.getIntLE(offset + 55);
int varPos3 = offset + 99 + buf.getIntLE(offset + 63);
int gradientSetLen = VarInt.peek(buf, varPos3);
if (gradientSetLen < 0) {
throw ProtocolException.negativeLength("GradientSet", gradientSetLen);
@@ -190,7 +200,7 @@ public class Model {
}
if ((nullBits[0] & 64) != 0) {
int varPos4 = offset + 91 + buf.getIntLE(offset + 59);
int varPos4 = offset + 99 + buf.getIntLE(offset + 67);
int gradientIdLen = VarInt.peek(buf, varPos4);
if (gradientIdLen < 0) {
throw ProtocolException.negativeLength("GradientId", gradientIdLen);
@@ -204,12 +214,12 @@ public class Model {
}
if ((nullBits[0] & 128) != 0) {
int varPos5 = offset + 91 + buf.getIntLE(offset + 63);
int varPos5 = offset + 99 + buf.getIntLE(offset + 71);
obj.camera = CameraSettings.deserialize(buf, varPos5);
}
if ((nullBits[1] & 1) != 0) {
int varPos6 = offset + 91 + buf.getIntLE(offset + 67);
int varPos6 = offset + 99 + buf.getIntLE(offset + 75);
int animationSetsCount = VarInt.peek(buf, varPos6);
if (animationSetsCount < 0) {
throw ProtocolException.negativeLength("AnimationSets", animationSetsCount);
@@ -245,7 +255,7 @@ public class Model {
}
if ((nullBits[1] & 2) != 0) {
int varPos7 = offset + 91 + buf.getIntLE(offset + 71);
int varPos7 = offset + 99 + buf.getIntLE(offset + 79);
int attachmentsCount = VarInt.peek(buf, varPos7);
if (attachmentsCount < 0) {
throw ProtocolException.negativeLength("Attachments", attachmentsCount);
@@ -270,7 +280,7 @@ public class Model {
}
if ((nullBits[1] & 4) != 0) {
int varPos8 = offset + 91 + buf.getIntLE(offset + 75);
int varPos8 = offset + 99 + buf.getIntLE(offset + 83);
int particlesCount = VarInt.peek(buf, varPos8);
if (particlesCount < 0) {
throw ProtocolException.negativeLength("Particles", particlesCount);
@@ -295,7 +305,7 @@ public class Model {
}
if ((nullBits[1] & 8) != 0) {
int varPos9 = offset + 91 + buf.getIntLE(offset + 79);
int varPos9 = offset + 99 + buf.getIntLE(offset + 87);
int trailsCount = VarInt.peek(buf, varPos9);
if (trailsCount < 0) {
throw ProtocolException.negativeLength("Trails", trailsCount);
@@ -320,7 +330,7 @@ public class Model {
}
if ((nullBits[1] & 16) != 0) {
int varPos10 = offset + 91 + buf.getIntLE(offset + 83);
int varPos10 = offset + 99 + buf.getIntLE(offset + 91);
int detailBoxesCount = VarInt.peek(buf, varPos10);
if (detailBoxesCount < 0) {
throw ProtocolException.negativeLength("DetailBoxes", detailBoxesCount);
@@ -376,7 +386,7 @@ public class Model {
}
if ((nullBits[1] & 32) != 0) {
int varPos11 = offset + 91 + buf.getIntLE(offset + 87);
int varPos11 = offset + 99 + buf.getIntLE(offset + 95);
obj.phobiaModel = deserialize(buf, varPos11);
}
@@ -385,10 +395,10 @@ public class Model {
public static int computeBytesConsumed(@Nonnull ByteBuf buf, int offset) {
byte[] nullBits = PacketIO.readBytes(buf, offset, 2);
int maxEnd = 91;
int maxEnd = 99;
if ((nullBits[0] & 4) != 0) {
int fieldOffset0 = buf.getIntLE(offset + 43);
int pos0 = offset + 91 + fieldOffset0;
int fieldOffset0 = buf.getIntLE(offset + 51);
int pos0 = offset + 99 + fieldOffset0;
int sl = VarInt.peek(buf, pos0);
pos0 += VarInt.length(buf, pos0) + sl;
if (pos0 - offset > maxEnd) {
@@ -397,8 +407,8 @@ public class Model {
}
if ((nullBits[0] & 8) != 0) {
int fieldOffset1 = buf.getIntLE(offset + 47);
int pos1 = offset + 91 + fieldOffset1;
int fieldOffset1 = buf.getIntLE(offset + 55);
int pos1 = offset + 99 + fieldOffset1;
int sl = VarInt.peek(buf, pos1);
pos1 += VarInt.length(buf, pos1) + sl;
if (pos1 - offset > maxEnd) {
@@ -407,8 +417,8 @@ public class Model {
}
if ((nullBits[0] & 16) != 0) {
int fieldOffset2 = buf.getIntLE(offset + 51);
int pos2 = offset + 91 + fieldOffset2;
int fieldOffset2 = buf.getIntLE(offset + 59);
int pos2 = offset + 99 + fieldOffset2;
int sl = VarInt.peek(buf, pos2);
pos2 += VarInt.length(buf, pos2) + sl;
if (pos2 - offset > maxEnd) {
@@ -417,8 +427,8 @@ public class Model {
}
if ((nullBits[0] & 32) != 0) {
int fieldOffset3 = buf.getIntLE(offset + 55);
int pos3 = offset + 91 + fieldOffset3;
int fieldOffset3 = buf.getIntLE(offset + 63);
int pos3 = offset + 99 + fieldOffset3;
int sl = VarInt.peek(buf, pos3);
pos3 += VarInt.length(buf, pos3) + sl;
if (pos3 - offset > maxEnd) {
@@ -427,8 +437,8 @@ public class Model {
}
if ((nullBits[0] & 64) != 0) {
int fieldOffset4 = buf.getIntLE(offset + 59);
int pos4 = offset + 91 + fieldOffset4;
int fieldOffset4 = buf.getIntLE(offset + 67);
int pos4 = offset + 99 + fieldOffset4;
int sl = VarInt.peek(buf, pos4);
pos4 += VarInt.length(buf, pos4) + sl;
if (pos4 - offset > maxEnd) {
@@ -437,8 +447,8 @@ public class Model {
}
if ((nullBits[0] & 128) != 0) {
int fieldOffset5 = buf.getIntLE(offset + 63);
int pos5 = offset + 91 + fieldOffset5;
int fieldOffset5 = buf.getIntLE(offset + 71);
int pos5 = offset + 99 + fieldOffset5;
pos5 += CameraSettings.computeBytesConsumed(buf, pos5);
if (pos5 - offset > maxEnd) {
maxEnd = pos5 - offset;
@@ -446,8 +456,8 @@ public class Model {
}
if ((nullBits[1] & 1) != 0) {
int fieldOffset6 = buf.getIntLE(offset + 67);
int pos6 = offset + 91 + fieldOffset6;
int fieldOffset6 = buf.getIntLE(offset + 75);
int pos6 = offset + 99 + fieldOffset6;
int dictLen = VarInt.peek(buf, pos6);
pos6 += VarInt.length(buf, pos6);
@@ -463,8 +473,8 @@ public class Model {
}
if ((nullBits[1] & 2) != 0) {
int fieldOffset7 = buf.getIntLE(offset + 71);
int pos7 = offset + 91 + fieldOffset7;
int fieldOffset7 = buf.getIntLE(offset + 79);
int pos7 = offset + 99 + fieldOffset7;
int arrLen = VarInt.peek(buf, pos7);
pos7 += VarInt.length(buf, pos7);
@@ -478,8 +488,8 @@ public class Model {
}
if ((nullBits[1] & 4) != 0) {
int fieldOffset8 = buf.getIntLE(offset + 75);
int pos8 = offset + 91 + fieldOffset8;
int fieldOffset8 = buf.getIntLE(offset + 83);
int pos8 = offset + 99 + fieldOffset8;
int arrLen = VarInt.peek(buf, pos8);
pos8 += VarInt.length(buf, pos8);
@@ -493,8 +503,8 @@ public class Model {
}
if ((nullBits[1] & 8) != 0) {
int fieldOffset9 = buf.getIntLE(offset + 79);
int pos9 = offset + 91 + fieldOffset9;
int fieldOffset9 = buf.getIntLE(offset + 87);
int pos9 = offset + 99 + fieldOffset9;
int arrLen = VarInt.peek(buf, pos9);
pos9 += VarInt.length(buf, pos9);
@@ -508,8 +518,8 @@ public class Model {
}
if ((nullBits[1] & 16) != 0) {
int fieldOffset10 = buf.getIntLE(offset + 83);
int pos10 = offset + 91 + fieldOffset10;
int fieldOffset10 = buf.getIntLE(offset + 91);
int pos10 = offset + 99 + fieldOffset10;
int dictLen = VarInt.peek(buf, pos10);
pos10 += VarInt.length(buf, pos10);
@@ -530,8 +540,8 @@ public class Model {
}
if ((nullBits[1] & 32) != 0) {
int fieldOffset11 = buf.getIntLE(offset + 87);
int pos11 = offset + 91 + fieldOffset11;
int fieldOffset11 = buf.getIntLE(offset + 95);
int pos11 = offset + 99 + fieldOffset11;
pos11 += computeBytesConsumed(buf, pos11);
if (pos11 - offset > maxEnd) {
maxEnd = pos11 - offset;
@@ -604,6 +614,8 @@ public class Model {
buf.writeFloatLE(this.scale);
buf.writeFloatLE(this.eyeHeight);
buf.writeFloatLE(this.crouchOffset);
buf.writeFloatLE(this.sittingOffset);
buf.writeFloatLE(this.sleepingOffset);
if (this.hitbox != null) {
this.hitbox.serialize(buf);
} else {
@@ -774,7 +786,7 @@ public class Model {
}
public int computeSize() {
int size = 91;
int size = 99;
if (this.assetId != null) {
size += PacketIO.stringSize(this.assetId);
}
@@ -857,17 +869,17 @@ public class Model {
}
public static ValidationResult validateStructure(@Nonnull ByteBuf buffer, int offset) {
if (buffer.readableBytes() - offset < 91) {
return ValidationResult.error("Buffer too small: expected at least 91 bytes");
if (buffer.readableBytes() - offset < 99) {
return ValidationResult.error("Buffer too small: expected at least 99 bytes");
} else {
byte[] nullBits = PacketIO.readBytes(buffer, offset, 2);
if ((nullBits[0] & 4) != 0) {
int assetIdOffset = buffer.getIntLE(offset + 43);
int assetIdOffset = buffer.getIntLE(offset + 51);
if (assetIdOffset < 0) {
return ValidationResult.error("Invalid offset for AssetId");
}
int pos = offset + 91 + assetIdOffset;
int pos = offset + 99 + assetIdOffset;
if (pos >= buffer.writerIndex()) {
return ValidationResult.error("Offset out of bounds for AssetId");
}
@@ -889,12 +901,12 @@ public class Model {
}
if ((nullBits[0] & 8) != 0) {
int pathOffset = buffer.getIntLE(offset + 47);
int pathOffset = buffer.getIntLE(offset + 55);
if (pathOffset < 0) {
return ValidationResult.error("Invalid offset for Path");
}
int posx = offset + 91 + pathOffset;
int posx = offset + 99 + pathOffset;
if (posx >= buffer.writerIndex()) {
return ValidationResult.error("Offset out of bounds for Path");
}
@@ -916,12 +928,12 @@ public class Model {
}
if ((nullBits[0] & 16) != 0) {
int textureOffset = buffer.getIntLE(offset + 51);
int textureOffset = buffer.getIntLE(offset + 59);
if (textureOffset < 0) {
return ValidationResult.error("Invalid offset for Texture");
}
int posxx = offset + 91 + textureOffset;
int posxx = offset + 99 + textureOffset;
if (posxx >= buffer.writerIndex()) {
return ValidationResult.error("Offset out of bounds for Texture");
}
@@ -943,12 +955,12 @@ public class Model {
}
if ((nullBits[0] & 32) != 0) {
int gradientSetOffset = buffer.getIntLE(offset + 55);
int gradientSetOffset = buffer.getIntLE(offset + 63);
if (gradientSetOffset < 0) {
return ValidationResult.error("Invalid offset for GradientSet");
}
int posxxx = offset + 91 + gradientSetOffset;
int posxxx = offset + 99 + gradientSetOffset;
if (posxxx >= buffer.writerIndex()) {
return ValidationResult.error("Offset out of bounds for GradientSet");
}
@@ -970,12 +982,12 @@ public class Model {
}
if ((nullBits[0] & 64) != 0) {
int gradientIdOffset = buffer.getIntLE(offset + 59);
int gradientIdOffset = buffer.getIntLE(offset + 67);
if (gradientIdOffset < 0) {
return ValidationResult.error("Invalid offset for GradientId");
}
int posxxxx = offset + 91 + gradientIdOffset;
int posxxxx = offset + 99 + gradientIdOffset;
if (posxxxx >= buffer.writerIndex()) {
return ValidationResult.error("Offset out of bounds for GradientId");
}
@@ -997,12 +1009,12 @@ public class Model {
}
if ((nullBits[0] & 128) != 0) {
int cameraOffset = buffer.getIntLE(offset + 63);
int cameraOffset = buffer.getIntLE(offset + 71);
if (cameraOffset < 0) {
return ValidationResult.error("Invalid offset for Camera");
}
int posxxxxx = offset + 91 + cameraOffset;
int posxxxxx = offset + 99 + cameraOffset;
if (posxxxxx >= buffer.writerIndex()) {
return ValidationResult.error("Offset out of bounds for Camera");
}
@@ -1016,12 +1028,12 @@ public class Model {
}
if ((nullBits[1] & 1) != 0) {
int animationSetsOffset = buffer.getIntLE(offset + 67);
int animationSetsOffset = buffer.getIntLE(offset + 75);
if (animationSetsOffset < 0) {
return ValidationResult.error("Invalid offset for AnimationSets");
}
int posxxxxxx = offset + 91 + animationSetsOffset;
int posxxxxxx = offset + 99 + animationSetsOffset;
if (posxxxxxx >= buffer.writerIndex()) {
return ValidationResult.error("Offset out of bounds for AnimationSets");
}
@@ -1058,12 +1070,12 @@ public class Model {
}
if ((nullBits[1] & 2) != 0) {
int attachmentsOffset = buffer.getIntLE(offset + 71);
int attachmentsOffset = buffer.getIntLE(offset + 79);
if (attachmentsOffset < 0) {
return ValidationResult.error("Invalid offset for Attachments");
}
int posxxxxxxx = offset + 91 + attachmentsOffset;
int posxxxxxxx = offset + 99 + attachmentsOffset;
if (posxxxxxxx >= buffer.writerIndex()) {
return ValidationResult.error("Offset out of bounds for Attachments");
}
@@ -1090,12 +1102,12 @@ public class Model {
}
if ((nullBits[1] & 4) != 0) {
int particlesOffset = buffer.getIntLE(offset + 75);
int particlesOffset = buffer.getIntLE(offset + 83);
if (particlesOffset < 0) {
return ValidationResult.error("Invalid offset for Particles");
}
int posxxxxxxxx = offset + 91 + particlesOffset;
int posxxxxxxxx = offset + 99 + particlesOffset;
if (posxxxxxxxx >= buffer.writerIndex()) {
return ValidationResult.error("Offset out of bounds for Particles");
}
@@ -1122,12 +1134,12 @@ public class Model {
}
if ((nullBits[1] & 8) != 0) {
int trailsOffset = buffer.getIntLE(offset + 79);
int trailsOffset = buffer.getIntLE(offset + 87);
if (trailsOffset < 0) {
return ValidationResult.error("Invalid offset for Trails");
}
int posxxxxxxxxx = offset + 91 + trailsOffset;
int posxxxxxxxxx = offset + 99 + trailsOffset;
if (posxxxxxxxxx >= buffer.writerIndex()) {
return ValidationResult.error("Offset out of bounds for Trails");
}
@@ -1154,12 +1166,12 @@ public class Model {
}
if ((nullBits[1] & 16) != 0) {
int detailBoxesOffset = buffer.getIntLE(offset + 83);
int detailBoxesOffset = buffer.getIntLE(offset + 91);
if (detailBoxesOffset < 0) {
return ValidationResult.error("Invalid offset for DetailBoxes");
}
int posxxxxxxxxxx = offset + 91 + detailBoxesOffset;
int posxxxxxxxxxx = offset + 99 + detailBoxesOffset;
if (posxxxxxxxxxx >= buffer.writerIndex()) {
return ValidationResult.error("Offset out of bounds for DetailBoxes");
}
@@ -1205,12 +1217,12 @@ public class Model {
}
if ((nullBits[1] & 32) != 0) {
int phobiaModelOffset = buffer.getIntLE(offset + 87);
int phobiaModelOffset = buffer.getIntLE(offset + 95);
if (phobiaModelOffset < 0) {
return ValidationResult.error("Invalid offset for PhobiaModel");
}
int posxxxxxxxxxxx = offset + 91 + phobiaModelOffset;
int posxxxxxxxxxxx = offset + 99 + phobiaModelOffset;
if (posxxxxxxxxxxx >= buffer.writerIndex()) {
return ValidationResult.error("Offset out of bounds for PhobiaModel");
}
@@ -1238,6 +1250,8 @@ public class Model {
copy.scale = this.scale;
copy.eyeHeight = this.eyeHeight;
copy.crouchOffset = this.crouchOffset;
copy.sittingOffset = this.sittingOffset;
copy.sleepingOffset = this.sleepingOffset;
if (this.animationSets != null) {
Map<String, AnimationSet> m = new HashMap<>();
@@ -1284,6 +1298,8 @@ public class Model {
&& this.scale == other.scale
&& this.eyeHeight == other.eyeHeight
&& this.crouchOffset == other.crouchOffset
&& this.sittingOffset == other.sittingOffset
&& this.sleepingOffset == other.sleepingOffset
&& Objects.equals(this.animationSets, other.animationSets)
&& Arrays.equals((Object[])this.attachments, (Object[])other.attachments)
&& Objects.equals(this.hitbox, other.hitbox)
@@ -1308,6 +1324,8 @@ public class Model {
result = 31 * result + Float.hashCode(this.scale);
result = 31 * result + Float.hashCode(this.eyeHeight);
result = 31 * result + Float.hashCode(this.crouchOffset);
result = 31 * result + Float.hashCode(this.sittingOffset);
result = 31 * result + Float.hashCode(this.sleepingOffset);
result = 31 * result + Objects.hashCode(this.animationSets);
result = 31 * result + Arrays.hashCode((Object[])this.attachments);
result = 31 * result + Objects.hashCode(this.hitbox);

View File

@@ -0,0 +1,122 @@
package com.hypixel.hytale.protocol;
import com.hypixel.hytale.protocol.io.ValidationResult;
import io.netty.buffer.ByteBuf;
import java.util.Objects;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class ModelUpdate extends ComponentUpdate {
public static final int NULLABLE_BIT_FIELD_SIZE = 1;
public static final int FIXED_BLOCK_SIZE = 5;
public static final int VARIABLE_FIELD_COUNT = 1;
public static final int VARIABLE_BLOCK_START = 5;
public static final int MAX_SIZE = 1677721600;
@Nullable
public Model model;
public float entityScale;
public ModelUpdate() {
}
public ModelUpdate(@Nullable Model model, float entityScale) {
this.model = model;
this.entityScale = entityScale;
}
public ModelUpdate(@Nonnull ModelUpdate other) {
this.model = other.model;
this.entityScale = other.entityScale;
}
@Nonnull
public static ModelUpdate deserialize(@Nonnull ByteBuf buf, int offset) {
ModelUpdate obj = new ModelUpdate();
byte nullBits = buf.getByte(offset);
obj.entityScale = buf.getFloatLE(offset + 1);
int pos = offset + 5;
if ((nullBits & 1) != 0) {
obj.model = Model.deserialize(buf, pos);
pos += Model.computeBytesConsumed(buf, pos);
}
return obj;
}
public static int computeBytesConsumed(@Nonnull ByteBuf buf, int offset) {
byte nullBits = buf.getByte(offset);
int pos = offset + 5;
if ((nullBits & 1) != 0) {
pos += Model.computeBytesConsumed(buf, pos);
}
return pos - offset;
}
@Override
public int serialize(@Nonnull ByteBuf buf) {
int startPos = buf.writerIndex();
byte nullBits = 0;
if (this.model != null) {
nullBits = (byte)(nullBits | 1);
}
buf.writeByte(nullBits);
buf.writeFloatLE(this.entityScale);
if (this.model != null) {
this.model.serialize(buf);
}
return buf.writerIndex() - startPos;
}
@Override
public int computeSize() {
int size = 5;
if (this.model != null) {
size += this.model.computeSize();
}
return size;
}
public static ValidationResult validateStructure(@Nonnull ByteBuf buffer, int offset) {
if (buffer.readableBytes() - offset < 5) {
return ValidationResult.error("Buffer too small: expected at least 5 bytes");
} else {
byte nullBits = buffer.getByte(offset);
int pos = offset + 5;
if ((nullBits & 1) != 0) {
ValidationResult modelResult = Model.validateStructure(buffer, pos);
if (!modelResult.isValid()) {
return ValidationResult.error("Invalid Model: " + modelResult.error());
}
pos += Model.computeBytesConsumed(buffer, pos);
}
return ValidationResult.OK;
}
}
public ModelUpdate clone() {
ModelUpdate copy = new ModelUpdate();
copy.model = this.model != null ? this.model.clone() : null;
copy.entityScale = this.entityScale;
return copy;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
} else {
return !(obj instanceof ModelUpdate other) ? false : Objects.equals(this.model, other.model) && this.entityScale == other.entityScale;
}
}
@Override
public int hashCode() {
return Objects.hash(this.model, this.entityScale);
}
}

View File

@@ -6,7 +6,7 @@ import java.util.Objects;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class MountedUpdate {
public class MountedUpdate extends ComponentUpdate {
public static final int NULLABLE_BIT_FIELD_SIZE = 1;
public static final int FIXED_BLOCK_SIZE = 48;
public static final int VARIABLE_FIELD_COUNT = 0;
@@ -58,7 +58,9 @@ public class MountedUpdate {
return 48;
}
public void serialize(@Nonnull ByteBuf buf) {
@Override
public int serialize(@Nonnull ByteBuf buf) {
int startPos = buf.writerIndex();
byte nullBits = 0;
if (this.attachmentOffset != null) {
nullBits = (byte)(nullBits | 1);
@@ -82,8 +84,11 @@ public class MountedUpdate {
} else {
buf.writeZero(30);
}
return buf.writerIndex() - startPos;
}
@Override
public int computeSize() {
return 48;
}

View File

@@ -0,0 +1,74 @@
package com.hypixel.hytale.protocol;
import com.hypixel.hytale.protocol.io.ValidationResult;
import io.netty.buffer.ByteBuf;
import java.util.Objects;
import javax.annotation.Nonnull;
public class MovementStatesUpdate extends ComponentUpdate {
public static final int NULLABLE_BIT_FIELD_SIZE = 0;
public static final int FIXED_BLOCK_SIZE = 22;
public static final int VARIABLE_FIELD_COUNT = 0;
public static final int VARIABLE_BLOCK_START = 22;
public static final int MAX_SIZE = 22;
@Nonnull
public MovementStates movementStates = new MovementStates();
public MovementStatesUpdate() {
}
public MovementStatesUpdate(@Nonnull MovementStates movementStates) {
this.movementStates = movementStates;
}
public MovementStatesUpdate(@Nonnull MovementStatesUpdate other) {
this.movementStates = other.movementStates;
}
@Nonnull
public static MovementStatesUpdate deserialize(@Nonnull ByteBuf buf, int offset) {
MovementStatesUpdate obj = new MovementStatesUpdate();
obj.movementStates = MovementStates.deserialize(buf, offset + 0);
return obj;
}
public static int computeBytesConsumed(@Nonnull ByteBuf buf, int offset) {
return 22;
}
@Override
public int serialize(@Nonnull ByteBuf buf) {
int startPos = buf.writerIndex();
this.movementStates.serialize(buf);
return buf.writerIndex() - startPos;
}
@Override
public int computeSize() {
return 22;
}
public static ValidationResult validateStructure(@Nonnull ByteBuf buffer, int offset) {
return buffer.readableBytes() - offset < 22 ? ValidationResult.error("Buffer too small: expected at least 22 bytes") : ValidationResult.OK;
}
public MovementStatesUpdate clone() {
MovementStatesUpdate copy = new MovementStatesUpdate();
copy.movementStates = this.movementStates.clone();
return copy;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
} else {
return obj instanceof MovementStatesUpdate other ? Objects.equals(this.movementStates, other.movementStates) : false;
}
}
@Override
public int hashCode() {
return Objects.hash(this.movementStates);
}
}

View File

@@ -0,0 +1,105 @@
package com.hypixel.hytale.protocol;
import com.hypixel.hytale.protocol.io.PacketIO;
import com.hypixel.hytale.protocol.io.ProtocolException;
import com.hypixel.hytale.protocol.io.ValidationResult;
import com.hypixel.hytale.protocol.io.VarInt;
import io.netty.buffer.ByteBuf;
import java.util.Objects;
import javax.annotation.Nonnull;
public class NameplateUpdate extends ComponentUpdate {
public static final int NULLABLE_BIT_FIELD_SIZE = 0;
public static final int FIXED_BLOCK_SIZE = 0;
public static final int VARIABLE_FIELD_COUNT = 1;
public static final int VARIABLE_BLOCK_START = 0;
public static final int MAX_SIZE = 16384005;
@Nonnull
public String text = "";
public NameplateUpdate() {
}
public NameplateUpdate(@Nonnull String text) {
this.text = text;
}
public NameplateUpdate(@Nonnull NameplateUpdate other) {
this.text = other.text;
}
@Nonnull
public static NameplateUpdate deserialize(@Nonnull ByteBuf buf, int offset) {
NameplateUpdate obj = new NameplateUpdate();
int pos = offset + 0;
int textLen = VarInt.peek(buf, pos);
if (textLen < 0) {
throw ProtocolException.negativeLength("Text", textLen);
} else if (textLen > 4096000) {
throw ProtocolException.stringTooLong("Text", textLen, 4096000);
} else {
int textVarLen = VarInt.length(buf, pos);
obj.text = PacketIO.readVarString(buf, pos, PacketIO.UTF8);
pos += textVarLen + textLen;
return obj;
}
}
public static int computeBytesConsumed(@Nonnull ByteBuf buf, int offset) {
int pos = offset + 0;
int sl = VarInt.peek(buf, pos);
pos += VarInt.length(buf, pos) + sl;
return pos - offset;
}
@Override
public int serialize(@Nonnull ByteBuf buf) {
int startPos = buf.writerIndex();
PacketIO.writeVarString(buf, this.text, 4096000);
return buf.writerIndex() - startPos;
}
@Override
public int computeSize() {
int size = 0;
return size + PacketIO.stringSize(this.text);
}
public static ValidationResult validateStructure(@Nonnull ByteBuf buffer, int offset) {
if (buffer.readableBytes() - offset < 0) {
return ValidationResult.error("Buffer too small: expected at least 0 bytes");
} else {
int pos = offset + 0;
int textLen = VarInt.peek(buffer, pos);
if (textLen < 0) {
return ValidationResult.error("Invalid string length for Text");
} else if (textLen > 4096000) {
return ValidationResult.error("Text exceeds max length 4096000");
} else {
pos += VarInt.length(buffer, pos);
pos += textLen;
return pos > buffer.writerIndex() ? ValidationResult.error("Buffer overflow reading Text") : ValidationResult.OK;
}
}
}
public NameplateUpdate clone() {
NameplateUpdate copy = new NameplateUpdate();
copy.text = this.text;
return copy;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
} else {
return obj instanceof NameplateUpdate other ? Objects.equals(this.text, other.text) : false;
}
}
@Override
public int hashCode() {
return Objects.hash(this.text);
}
}

View File

@@ -0,0 +1,27 @@
package com.hypixel.hytale.protocol;
public enum NetworkChannel {
Default(0),
Chunks(1),
WorldMap(2);
public static final NetworkChannel[] VALUES = values();
public static final int COUNT = VALUES.length;
private final int value;
private NetworkChannel(int value) {
this.value = value;
}
public int getValue() {
return this.value;
}
public static NetworkChannel fromValue(int value) {
if (value >= 0 && value < VALUES.length) {
return VALUES[value];
} else {
throw new IllegalArgumentException("Invalid network channel: " + value);
}
}
}

View File

@@ -0,0 +1,51 @@
package com.hypixel.hytale.protocol;
import com.hypixel.hytale.protocol.io.ValidationResult;
import io.netty.buffer.ByteBuf;
import javax.annotation.Nonnull;
public class NewSpawnUpdate extends ComponentUpdate {
public static final int NULLABLE_BIT_FIELD_SIZE = 0;
public static final int FIXED_BLOCK_SIZE = 0;
public static final int VARIABLE_FIELD_COUNT = 0;
public static final int VARIABLE_BLOCK_START = 0;
public static final int MAX_SIZE = 0;
@Nonnull
public static NewSpawnUpdate deserialize(@Nonnull ByteBuf buf, int offset) {
return new NewSpawnUpdate();
}
public static int computeBytesConsumed(@Nonnull ByteBuf buf, int offset) {
return 0;
}
@Override
public int serialize(@Nonnull ByteBuf buf) {
int startPos = buf.writerIndex();
return buf.writerIndex() - startPos;
}
@Override
public int computeSize() {
return 0;
}
public static ValidationResult validateStructure(@Nonnull ByteBuf buffer, int offset) {
return buffer.readableBytes() - offset < 0 ? ValidationResult.error("Buffer too small: expected at least 0 bytes") : ValidationResult.OK;
}
public NewSpawnUpdate clone() {
return new NewSpawnUpdate();
}
@Override
public boolean equals(Object obj) {
return this == obj ? true : obj instanceof NewSpawnUpdate other;
}
@Override
public int hashCode() {
return 0;
}
}

View File

@@ -6,6 +6,8 @@ import javax.annotation.Nonnull;
public interface Packet {
int getId();
NetworkChannel getChannel();
void serialize(@Nonnull ByteBuf var1);
int computeSize();

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,116 @@
package com.hypixel.hytale.protocol;
import com.hypixel.hytale.protocol.io.ValidationResult;
import io.netty.buffer.ByteBuf;
import java.util.Objects;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class PlayerSkinUpdate extends ComponentUpdate {
public static final int NULLABLE_BIT_FIELD_SIZE = 1;
public static final int FIXED_BLOCK_SIZE = 1;
public static final int VARIABLE_FIELD_COUNT = 1;
public static final int VARIABLE_BLOCK_START = 1;
public static final int MAX_SIZE = 327680184;
@Nullable
public PlayerSkin skin;
public PlayerSkinUpdate() {
}
public PlayerSkinUpdate(@Nullable PlayerSkin skin) {
this.skin = skin;
}
public PlayerSkinUpdate(@Nonnull PlayerSkinUpdate other) {
this.skin = other.skin;
}
@Nonnull
public static PlayerSkinUpdate deserialize(@Nonnull ByteBuf buf, int offset) {
PlayerSkinUpdate obj = new PlayerSkinUpdate();
byte nullBits = buf.getByte(offset);
int pos = offset + 1;
if ((nullBits & 1) != 0) {
obj.skin = PlayerSkin.deserialize(buf, pos);
pos += PlayerSkin.computeBytesConsumed(buf, pos);
}
return obj;
}
public static int computeBytesConsumed(@Nonnull ByteBuf buf, int offset) {
byte nullBits = buf.getByte(offset);
int pos = offset + 1;
if ((nullBits & 1) != 0) {
pos += PlayerSkin.computeBytesConsumed(buf, pos);
}
return pos - offset;
}
@Override
public int serialize(@Nonnull ByteBuf buf) {
int startPos = buf.writerIndex();
byte nullBits = 0;
if (this.skin != null) {
nullBits = (byte)(nullBits | 1);
}
buf.writeByte(nullBits);
if (this.skin != null) {
this.skin.serialize(buf);
}
return buf.writerIndex() - startPos;
}
@Override
public int computeSize() {
int size = 1;
if (this.skin != null) {
size += this.skin.computeSize();
}
return size;
}
public static ValidationResult validateStructure(@Nonnull ByteBuf buffer, int offset) {
if (buffer.readableBytes() - offset < 1) {
return ValidationResult.error("Buffer too small: expected at least 1 bytes");
} else {
byte nullBits = buffer.getByte(offset);
int pos = offset + 1;
if ((nullBits & 1) != 0) {
ValidationResult skinResult = PlayerSkin.validateStructure(buffer, pos);
if (!skinResult.isValid()) {
return ValidationResult.error("Invalid Skin: " + skinResult.error());
}
pos += PlayerSkin.computeBytesConsumed(buffer, pos);
}
return ValidationResult.OK;
}
}
public PlayerSkinUpdate clone() {
PlayerSkinUpdate copy = new PlayerSkinUpdate();
copy.skin = this.skin != null ? this.skin.clone() : null;
return copy;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
} else {
return obj instanceof PlayerSkinUpdate other ? Objects.equals(this.skin, other.skin) : false;
}
}
@Override
public int hashCode() {
return Objects.hash(this.skin);
}
}

View File

@@ -0,0 +1,76 @@
package com.hypixel.hytale.protocol;
import com.hypixel.hytale.protocol.io.PacketIO;
import com.hypixel.hytale.protocol.io.ValidationResult;
import io.netty.buffer.ByteBuf;
import java.util.Objects;
import java.util.UUID;
import javax.annotation.Nonnull;
public class PredictionUpdate extends ComponentUpdate {
public static final int NULLABLE_BIT_FIELD_SIZE = 0;
public static final int FIXED_BLOCK_SIZE = 16;
public static final int VARIABLE_FIELD_COUNT = 0;
public static final int VARIABLE_BLOCK_START = 16;
public static final int MAX_SIZE = 16;
@Nonnull
public UUID predictionId = new UUID(0L, 0L);
public PredictionUpdate() {
}
public PredictionUpdate(@Nonnull UUID predictionId) {
this.predictionId = predictionId;
}
public PredictionUpdate(@Nonnull PredictionUpdate other) {
this.predictionId = other.predictionId;
}
@Nonnull
public static PredictionUpdate deserialize(@Nonnull ByteBuf buf, int offset) {
PredictionUpdate obj = new PredictionUpdate();
obj.predictionId = PacketIO.readUUID(buf, offset + 0);
return obj;
}
public static int computeBytesConsumed(@Nonnull ByteBuf buf, int offset) {
return 16;
}
@Override
public int serialize(@Nonnull ByteBuf buf) {
int startPos = buf.writerIndex();
PacketIO.writeUUID(buf, this.predictionId);
return buf.writerIndex() - startPos;
}
@Override
public int computeSize() {
return 16;
}
public static ValidationResult validateStructure(@Nonnull ByteBuf buffer, int offset) {
return buffer.readableBytes() - offset < 16 ? ValidationResult.error("Buffer too small: expected at least 16 bytes") : ValidationResult.OK;
}
public PredictionUpdate clone() {
PredictionUpdate copy = new PredictionUpdate();
copy.predictionId = this.predictionId;
return copy;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
} else {
return obj instanceof PredictionUpdate other ? Objects.equals(this.predictionId, other.predictionId) : false;
}
}
@Override
public int hashCode() {
return Objects.hash(this.predictionId);
}
}

View File

@@ -0,0 +1,51 @@
package com.hypixel.hytale.protocol;
import com.hypixel.hytale.protocol.io.ValidationResult;
import io.netty.buffer.ByteBuf;
import javax.annotation.Nonnull;
public class PropUpdate extends ComponentUpdate {
public static final int NULLABLE_BIT_FIELD_SIZE = 0;
public static final int FIXED_BLOCK_SIZE = 0;
public static final int VARIABLE_FIELD_COUNT = 0;
public static final int VARIABLE_BLOCK_START = 0;
public static final int MAX_SIZE = 0;
@Nonnull
public static PropUpdate deserialize(@Nonnull ByteBuf buf, int offset) {
return new PropUpdate();
}
public static int computeBytesConsumed(@Nonnull ByteBuf buf, int offset) {
return 0;
}
@Override
public int serialize(@Nonnull ByteBuf buf) {
int startPos = buf.writerIndex();
return buf.writerIndex() - startPos;
}
@Override
public int computeSize() {
return 0;
}
public static ValidationResult validateStructure(@Nonnull ByteBuf buffer, int offset) {
return buffer.readableBytes() - offset < 0 ? ValidationResult.error("Buffer too small: expected at least 0 bytes") : ValidationResult.OK;
}
public PropUpdate clone() {
return new PropUpdate();
}
@Override
public boolean equals(Object obj) {
return this == obj ? true : obj instanceof PropUpdate other;
}
@Override
public int hashCode() {
return 0;
}
}

View File

@@ -1,11 +1,11 @@
package com.hypixel.hytale.protocol;
public final class ProtocolSettings {
public static final int PROTOCOL_CRC = 672031543;
public static final int PROTOCOL_CRC = -1356075132;
public static final int PROTOCOL_VERSION = 2;
public static final int PROTOCOL_BUILD_NUMBER = 12;
public static final int PACKET_COUNT = 270;
public static final int STRUCT_COUNT = 318;
public static final int PROTOCOL_BUILD_NUMBER = 20;
public static final int PACKET_COUNT = 268;
public static final int STRUCT_COUNT = 339;
public static final int ENUM_COUNT = 137;
public static final int MAX_PACKET_SIZE = 1677721600;
@@ -13,6 +13,6 @@ public final class ProtocolSettings {
}
public static boolean validateCrc(int crc) {
return 672031543 == crc;
return -1356075132 == crc;
}
}

View File

@@ -0,0 +1,73 @@
package com.hypixel.hytale.protocol;
import com.hypixel.hytale.protocol.io.ValidationResult;
import io.netty.buffer.ByteBuf;
import java.util.Objects;
import javax.annotation.Nonnull;
public class RepulsionUpdate extends ComponentUpdate {
public static final int NULLABLE_BIT_FIELD_SIZE = 0;
public static final int FIXED_BLOCK_SIZE = 4;
public static final int VARIABLE_FIELD_COUNT = 0;
public static final int VARIABLE_BLOCK_START = 4;
public static final int MAX_SIZE = 4;
public int repulsionConfigIndex;
public RepulsionUpdate() {
}
public RepulsionUpdate(int repulsionConfigIndex) {
this.repulsionConfigIndex = repulsionConfigIndex;
}
public RepulsionUpdate(@Nonnull RepulsionUpdate other) {
this.repulsionConfigIndex = other.repulsionConfigIndex;
}
@Nonnull
public static RepulsionUpdate deserialize(@Nonnull ByteBuf buf, int offset) {
RepulsionUpdate obj = new RepulsionUpdate();
obj.repulsionConfigIndex = buf.getIntLE(offset + 0);
return obj;
}
public static int computeBytesConsumed(@Nonnull ByteBuf buf, int offset) {
return 4;
}
@Override
public int serialize(@Nonnull ByteBuf buf) {
int startPos = buf.writerIndex();
buf.writeIntLE(this.repulsionConfigIndex);
return buf.writerIndex() - startPos;
}
@Override
public int computeSize() {
return 4;
}
public static ValidationResult validateStructure(@Nonnull ByteBuf buffer, int offset) {
return buffer.readableBytes() - offset < 4 ? ValidationResult.error("Buffer too small: expected at least 4 bytes") : ValidationResult.OK;
}
public RepulsionUpdate clone() {
RepulsionUpdate copy = new RepulsionUpdate();
copy.repulsionConfigIndex = this.repulsionConfigIndex;
return copy;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
} else {
return obj instanceof RepulsionUpdate other ? this.repulsionConfigIndex == other.repulsionConfigIndex : false;
}
}
@Override
public int hashCode() {
return Objects.hash(this.repulsionConfigIndex);
}
}

View File

@@ -0,0 +1,51 @@
package com.hypixel.hytale.protocol;
import com.hypixel.hytale.protocol.io.ValidationResult;
import io.netty.buffer.ByteBuf;
import javax.annotation.Nonnull;
public class RespondToHitUpdate extends ComponentUpdate {
public static final int NULLABLE_BIT_FIELD_SIZE = 0;
public static final int FIXED_BLOCK_SIZE = 0;
public static final int VARIABLE_FIELD_COUNT = 0;
public static final int VARIABLE_BLOCK_START = 0;
public static final int MAX_SIZE = 0;
@Nonnull
public static RespondToHitUpdate deserialize(@Nonnull ByteBuf buf, int offset) {
return new RespondToHitUpdate();
}
public static int computeBytesConsumed(@Nonnull ByteBuf buf, int offset) {
return 0;
}
@Override
public int serialize(@Nonnull ByteBuf buf) {
int startPos = buf.writerIndex();
return buf.writerIndex() - startPos;
}
@Override
public int computeSize() {
return 0;
}
public static ValidationResult validateStructure(@Nonnull ByteBuf buffer, int offset) {
return buffer.readableBytes() - offset < 0 ? ValidationResult.error("Buffer too small: expected at least 0 bytes") : ValidationResult.OK;
}
public RespondToHitUpdate clone() {
return new RespondToHitUpdate();
}
@Override
public boolean equals(Object obj) {
return this == obj ? true : obj instanceof RespondToHitUpdate other;
}
@Override
public int hashCode() {
return 0;
}
}

View File

@@ -0,0 +1,4 @@
package com.hypixel.hytale.protocol;
public interface ToClientPacket extends Packet {
}

View File

@@ -0,0 +1,4 @@
package com.hypixel.hytale.protocol;
public interface ToServerPacket extends Packet {
}

View File

@@ -0,0 +1,74 @@
package com.hypixel.hytale.protocol;
import com.hypixel.hytale.protocol.io.ValidationResult;
import io.netty.buffer.ByteBuf;
import java.util.Objects;
import javax.annotation.Nonnull;
public class TransformUpdate extends ComponentUpdate {
public static final int NULLABLE_BIT_FIELD_SIZE = 0;
public static final int FIXED_BLOCK_SIZE = 49;
public static final int VARIABLE_FIELD_COUNT = 0;
public static final int VARIABLE_BLOCK_START = 49;
public static final int MAX_SIZE = 49;
@Nonnull
public ModelTransform transform = new ModelTransform();
public TransformUpdate() {
}
public TransformUpdate(@Nonnull ModelTransform transform) {
this.transform = transform;
}
public TransformUpdate(@Nonnull TransformUpdate other) {
this.transform = other.transform;
}
@Nonnull
public static TransformUpdate deserialize(@Nonnull ByteBuf buf, int offset) {
TransformUpdate obj = new TransformUpdate();
obj.transform = ModelTransform.deserialize(buf, offset + 0);
return obj;
}
public static int computeBytesConsumed(@Nonnull ByteBuf buf, int offset) {
return 49;
}
@Override
public int serialize(@Nonnull ByteBuf buf) {
int startPos = buf.writerIndex();
this.transform.serialize(buf);
return buf.writerIndex() - startPos;
}
@Override
public int computeSize() {
return 49;
}
public static ValidationResult validateStructure(@Nonnull ByteBuf buffer, int offset) {
return buffer.readableBytes() - offset < 49 ? ValidationResult.error("Buffer too small: expected at least 49 bytes") : ValidationResult.OK;
}
public TransformUpdate clone() {
TransformUpdate copy = new TransformUpdate();
copy.transform = this.transform.clone();
return copy;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
} else {
return obj instanceof TransformUpdate other ? Objects.equals(this.transform, other.transform) : false;
}
}
@Override
public int hashCode() {
return Objects.hash(this.transform);
}
}

View File

@@ -0,0 +1,124 @@
package com.hypixel.hytale.protocol;
import com.hypixel.hytale.protocol.io.ProtocolException;
import com.hypixel.hytale.protocol.io.ValidationResult;
import com.hypixel.hytale.protocol.io.VarInt;
import io.netty.buffer.ByteBuf;
import java.util.Arrays;
import javax.annotation.Nonnull;
public class UIComponentsUpdate extends ComponentUpdate {
public static final int NULLABLE_BIT_FIELD_SIZE = 0;
public static final int FIXED_BLOCK_SIZE = 0;
public static final int VARIABLE_FIELD_COUNT = 1;
public static final int VARIABLE_BLOCK_START = 0;
public static final int MAX_SIZE = 16384005;
@Nonnull
public int[] components = new int[0];
public UIComponentsUpdate() {
}
public UIComponentsUpdate(@Nonnull int[] components) {
this.components = components;
}
public UIComponentsUpdate(@Nonnull UIComponentsUpdate other) {
this.components = other.components;
}
@Nonnull
public static UIComponentsUpdate deserialize(@Nonnull ByteBuf buf, int offset) {
UIComponentsUpdate obj = new UIComponentsUpdate();
int pos = offset + 0;
int componentsCount = VarInt.peek(buf, pos);
if (componentsCount < 0) {
throw ProtocolException.negativeLength("Components", componentsCount);
} else if (componentsCount > 4096000) {
throw ProtocolException.arrayTooLong("Components", componentsCount, 4096000);
} else {
int componentsVarLen = VarInt.size(componentsCount);
if (pos + componentsVarLen + componentsCount * 4L > buf.readableBytes()) {
throw ProtocolException.bufferTooSmall("Components", pos + componentsVarLen + componentsCount * 4, buf.readableBytes());
} else {
pos += componentsVarLen;
obj.components = new int[componentsCount];
for (int i = 0; i < componentsCount; i++) {
obj.components[i] = buf.getIntLE(pos + i * 4);
}
pos += componentsCount * 4;
return obj;
}
}
}
public static int computeBytesConsumed(@Nonnull ByteBuf buf, int offset) {
int pos = offset + 0;
int arrLen = VarInt.peek(buf, pos);
pos += VarInt.length(buf, pos) + arrLen * 4;
return pos - offset;
}
@Override
public int serialize(@Nonnull ByteBuf buf) {
int startPos = buf.writerIndex();
if (this.components.length > 4096000) {
throw ProtocolException.arrayTooLong("Components", this.components.length, 4096000);
} else {
VarInt.write(buf, this.components.length);
for (int item : this.components) {
buf.writeIntLE(item);
}
return buf.writerIndex() - startPos;
}
}
@Override
public int computeSize() {
int size = 0;
return size + VarInt.size(this.components.length) + this.components.length * 4;
}
public static ValidationResult validateStructure(@Nonnull ByteBuf buffer, int offset) {
if (buffer.readableBytes() - offset < 0) {
return ValidationResult.error("Buffer too small: expected at least 0 bytes");
} else {
int pos = offset + 0;
int componentsCount = VarInt.peek(buffer, pos);
if (componentsCount < 0) {
return ValidationResult.error("Invalid array count for Components");
} else if (componentsCount > 4096000) {
return ValidationResult.error("Components exceeds max length 4096000");
} else {
pos += VarInt.length(buffer, pos);
pos += componentsCount * 4;
return pos > buffer.writerIndex() ? ValidationResult.error("Buffer overflow reading Components") : ValidationResult.OK;
}
}
}
public UIComponentsUpdate clone() {
UIComponentsUpdate copy = new UIComponentsUpdate();
copy.components = Arrays.copyOf(this.components, this.components.length);
return copy;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
} else {
return obj instanceof UIComponentsUpdate other ? Arrays.equals(this.components, other.components) : false;
}
}
@Override
public int hashCode() {
int result = 1;
return 31 * result + Arrays.hashCode(this.components);
}
}

View File

@@ -305,7 +305,7 @@ public final class PacketIO {
if (id == null) {
throw new ProtocolException("Unknown packet type: " + packetClass.getName());
} else {
PacketRegistry.PacketInfo info = PacketRegistry.getById(id);
PacketRegistry.PacketInfo info = PacketRegistry.getToClientPacketById(id);
int lengthIndex = out.writerIndex();
out.writeIntLE(0);
out.writeIntLE(id);
@@ -351,7 +351,7 @@ public final class PacketIO {
@Nonnull
public static Packet readFramedPacket(@Nonnull ByteBuf in, int payloadLength, @Nonnull PacketStatsRecorder statsRecorder) {
int packetId = in.readIntLE();
PacketRegistry.PacketInfo info = PacketRegistry.getById(packetId);
PacketRegistry.PacketInfo info = PacketRegistry.getToServerPacketById(packetId);
if (info == null) {
in.skipBytes(payloadLength);
throw new ProtocolException("Unknown packet ID: " + packetId);

View File

@@ -1,5 +1,6 @@
package com.hypixel.hytale.protocol.io.netty;
import com.hypixel.hytale.protocol.NetworkChannel;
import com.hypixel.hytale.protocol.PacketRegistry;
import com.hypixel.hytale.protocol.io.PacketIO;
import com.hypixel.hytale.protocol.io.PacketStatsRecorder;
@@ -80,30 +81,36 @@ public class PacketDecoder extends ByteToMessageDecoder {
int payloadLength = in.readIntLE();
if (payloadLength >= 0 && payloadLength <= 1677721600) {
int packetId = in.readIntLE();
PacketRegistry.PacketInfo packetInfo = PacketRegistry.getById(packetId);
PacketRegistry.PacketInfo packetInfo = PacketRegistry.getToServerPacketById(packetId);
if (packetInfo == null) {
in.skipBytes(in.readableBytes());
ProtocolUtil.closeConnection(ctx.channel());
} else if (payloadLength > packetInfo.maxSize()) {
in.skipBytes(in.readableBytes());
ProtocolUtil.closeConnection(ctx.channel());
} else if (in.readableBytes() < payloadLength) {
in.resetReaderIndex();
} else {
PacketStatsRecorder statsRecorder = ctx.channel().attr(PacketStatsRecorder.CHANNEL_KEY).get();
if (statsRecorder == null) {
statsRecorder = PacketStatsRecorder.NOOP;
}
NetworkChannel channelVal = ctx.channel().attr(ProtocolUtil.STREAM_CHANNEL_KEY).get();
if (channelVal != null && channelVal != packetInfo.channel()) {
in.skipBytes(in.readableBytes());
ProtocolUtil.closeConnection(ctx.channel());
} else if (in.readableBytes() < payloadLength) {
in.resetReaderIndex();
} else {
PacketStatsRecorder statsRecorder = ctx.channel().attr(PacketStatsRecorder.CHANNEL_KEY).get();
if (statsRecorder == null) {
statsRecorder = PacketStatsRecorder.NOOP;
}
try {
out.add(PacketIO.readFramedPacketWithInfo(in, payloadLength, packetInfo, statsRecorder));
this.lastPacketTimeNanos = System.nanoTime();
} catch (ProtocolException var9) {
in.skipBytes(in.readableBytes());
ProtocolUtil.closeConnection(ctx.channel());
} catch (IndexOutOfBoundsException var10) {
in.skipBytes(in.readableBytes());
ProtocolUtil.closeConnection(ctx.channel());
try {
out.add(PacketIO.readFramedPacketWithInfo(in, payloadLength, packetInfo, statsRecorder));
this.lastPacketTimeNanos = System.nanoTime();
} catch (ProtocolException var10) {
in.skipBytes(in.readableBytes());
ProtocolUtil.closeConnection(ctx.channel());
} catch (IndexOutOfBoundsException var11) {
in.skipBytes(in.readableBytes());
ProtocolUtil.closeConnection(ctx.channel());
}
}
}
} else {

View File

@@ -1,6 +1,7 @@
package com.hypixel.hytale.protocol.io.netty;
import com.hypixel.hytale.protocol.CachedPacket;
import com.hypixel.hytale.protocol.NetworkChannel;
import com.hypixel.hytale.protocol.Packet;
import com.hypixel.hytale.protocol.io.PacketIO;
import com.hypixel.hytale.protocol.io.PacketStatsRecorder;
@@ -20,11 +21,16 @@ public class PacketEncoder extends MessageToByteEncoder<Packet> {
packetClass = (Class<? extends Packet>)packet.getClass();
}
PacketStatsRecorder statsRecorder = ctx.channel().attr(PacketStatsRecorder.CHANNEL_KEY).get();
if (statsRecorder == null) {
statsRecorder = PacketStatsRecorder.NOOP;
}
NetworkChannel channelAttr = ctx.channel().attr(ProtocolUtil.STREAM_CHANNEL_KEY).get();
if (channelAttr != null && channelAttr != packet.getChannel()) {
throw new IllegalArgumentException("Packet channel " + packet.getChannel() + " does not match stream channel " + channelAttr);
} else {
PacketStatsRecorder statsRecorder = ctx.channel().attr(PacketStatsRecorder.CHANNEL_KEY).get();
if (statsRecorder == null) {
statsRecorder = PacketStatsRecorder.NOOP;
}
PacketIO.writeFramedPacket(packet, packetClass, out, statsRecorder);
PacketIO.writeFramedPacket(packet, packetClass, out, statsRecorder);
}
}
}

View File

@@ -1,5 +1,6 @@
package com.hypixel.hytale.protocol.io.netty;
import com.hypixel.hytale.protocol.NetworkChannel;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
@@ -13,6 +14,7 @@ import java.time.Duration;
import javax.annotation.Nonnull;
public final class ProtocolUtil {
public static final AttributeKey<NetworkChannel> STREAM_CHANNEL_KEY = AttributeKey.newInstance("STREAM_CHANNEL_ID");
public static final AttributeKey<Duration> PACKET_TIMEOUT_KEY = AttributeKey.newInstance("PACKET_TIMEOUT");
public static final int APPLICATION_NO_ERROR = 0;
public static final int APPLICATION_RATE_LIMITED = 1;

View File

@@ -1,6 +1,8 @@
package com.hypixel.hytale.protocol.packets.asseteditor;
import com.hypixel.hytale.protocol.NetworkChannel;
import com.hypixel.hytale.protocol.Packet;
import com.hypixel.hytale.protocol.ToServerPacket;
import com.hypixel.hytale.protocol.io.PacketIO;
import com.hypixel.hytale.protocol.io.ProtocolException;
import com.hypixel.hytale.protocol.io.ValidationResult;
@@ -10,7 +12,7 @@ import java.util.Objects;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class AssetEditorActivateButton implements Packet {
public class AssetEditorActivateButton implements Packet, ToServerPacket {
public static final int PACKET_ID = 335;
public static final boolean IS_COMPRESSED = false;
public static final int NULLABLE_BIT_FIELD_SIZE = 1;
@@ -26,6 +28,11 @@ public class AssetEditorActivateButton implements Packet {
return 335;
}
@Override
public NetworkChannel getChannel() {
return NetworkChannel.Default;
}
public AssetEditorActivateButton() {
}

View File

@@ -1,6 +1,8 @@
package com.hypixel.hytale.protocol.packets.asseteditor;
import com.hypixel.hytale.protocol.NetworkChannel;
import com.hypixel.hytale.protocol.Packet;
import com.hypixel.hytale.protocol.ToClientPacket;
import com.hypixel.hytale.protocol.io.PacketIO;
import com.hypixel.hytale.protocol.io.ProtocolException;
import com.hypixel.hytale.protocol.io.ValidationResult;
@@ -11,7 +13,7 @@ import java.util.Objects;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class AssetEditorAssetListSetup implements Packet {
public class AssetEditorAssetListSetup implements Packet, ToClientPacket {
public static final int PACKET_ID = 319;
public static final boolean IS_COMPRESSED = true;
public static final int NULLABLE_BIT_FIELD_SIZE = 1;
@@ -33,6 +35,11 @@ public class AssetEditorAssetListSetup implements Packet {
return 319;
}
@Override
public NetworkChannel getChannel() {
return NetworkChannel.Default;
}
public AssetEditorAssetListSetup() {
}

View File

@@ -1,6 +1,8 @@
package com.hypixel.hytale.protocol.packets.asseteditor;
import com.hypixel.hytale.protocol.NetworkChannel;
import com.hypixel.hytale.protocol.Packet;
import com.hypixel.hytale.protocol.ToClientPacket;
import com.hypixel.hytale.protocol.io.PacketIO;
import com.hypixel.hytale.protocol.io.ProtocolException;
import com.hypixel.hytale.protocol.io.ValidationResult;
@@ -11,7 +13,7 @@ import java.util.Objects;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class AssetEditorAssetListUpdate implements Packet {
public class AssetEditorAssetListUpdate implements Packet, ToClientPacket {
public static final int PACKET_ID = 320;
public static final boolean IS_COMPRESSED = true;
public static final int NULLABLE_BIT_FIELD_SIZE = 1;
@@ -31,6 +33,11 @@ public class AssetEditorAssetListUpdate implements Packet {
return 320;
}
@Override
public NetworkChannel getChannel() {
return NetworkChannel.Default;
}
public AssetEditorAssetListUpdate() {
}

Some files were not shown because too many files have changed in this diff Show More