2026.02.11-255364b8e
This commit is contained in:
@@ -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<>();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -177,6 +177,8 @@ public class ObjectiveLocationMarkerSystems {
|
||||
model.getGradientId(),
|
||||
model.getEyeHeight(),
|
||||
model.getCrouchOffset(),
|
||||
model.getSittingOffset(),
|
||||
model.getSleepingOffset(),
|
||||
model.getAnimationSetMap(),
|
||||
model.getCamera(),
|
||||
model.getLight(),
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -38,6 +38,7 @@ public class FieldFunctionPositionProvider extends PositionProvider {
|
||||
for (FieldFunctionPositionProvider.Delimiter d : this.delimiters) {
|
||||
if (d.isInside(value)) {
|
||||
context.consumer.accept(p);
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
35
src/com/hypixel/hytale/builtin/randomtick/RandomTick.java
Normal file
35
src/com/hypixel/hytale/builtin/randomtick/RandomTick.java
Normal 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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
114
src/com/hypixel/hytale/builtin/randomtick/RandomTickSystem.java
Normal file
114
src/com/hypixel/hytale/builtin/randomtick/RandomTickSystem.java
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
|
||||
@@ -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('}')) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
179
src/com/hypixel/hytale/protocol/ActiveAnimationsUpdate.java
Normal file
179
src/com/hypixel/hytale/protocol/ActiveAnimationsUpdate.java
Normal 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);
|
||||
}
|
||||
}
|
||||
124
src/com/hypixel/hytale/protocol/AudioUpdate.java
Normal file
124
src/com/hypixel/hytale/protocol/AudioUpdate.java
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
79
src/com/hypixel/hytale/protocol/BlockUpdate.java
Normal file
79
src/com/hypixel/hytale/protocol/BlockUpdate.java
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
74
src/com/hypixel/hytale/protocol/DynamicLightUpdate.java
Normal file
74
src/com/hypixel/hytale/protocol/DynamicLightUpdate.java
Normal 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);
|
||||
}
|
||||
}
|
||||
144
src/com/hypixel/hytale/protocol/EntityEffectsUpdate.java
Normal file
144
src/com/hypixel/hytale/protocol/EntityEffectsUpdate.java
Normal 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);
|
||||
}
|
||||
}
|
||||
193
src/com/hypixel/hytale/protocol/EntityStatsUpdate.java
Normal file
193
src/com/hypixel/hytale/protocol/EntityStatsUpdate.java
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
73
src/com/hypixel/hytale/protocol/HitboxCollisionUpdate.java
Normal file
73
src/com/hypixel/hytale/protocol/HitboxCollisionUpdate.java
Normal 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);
|
||||
}
|
||||
}
|
||||
51
src/com/hypixel/hytale/protocol/IntangibleUpdate.java
Normal file
51
src/com/hypixel/hytale/protocol/IntangibleUpdate.java
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
241
src/com/hypixel/hytale/protocol/InteractionsUpdate.java
Normal file
241
src/com/hypixel/hytale/protocol/InteractionsUpdate.java
Normal 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);
|
||||
}
|
||||
}
|
||||
51
src/com/hypixel/hytale/protocol/InvulnerableUpdate.java
Normal file
51
src/com/hypixel/hytale/protocol/InvulnerableUpdate.java
Normal 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;
|
||||
}
|
||||
}
|
||||
96
src/com/hypixel/hytale/protocol/ItemUpdate.java
Normal file
96
src/com/hypixel/hytale/protocol/ItemUpdate.java
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
122
src/com/hypixel/hytale/protocol/ModelUpdate.java
Normal file
122
src/com/hypixel/hytale/protocol/ModelUpdate.java
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
74
src/com/hypixel/hytale/protocol/MovementStatesUpdate.java
Normal file
74
src/com/hypixel/hytale/protocol/MovementStatesUpdate.java
Normal 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);
|
||||
}
|
||||
}
|
||||
105
src/com/hypixel/hytale/protocol/NameplateUpdate.java
Normal file
105
src/com/hypixel/hytale/protocol/NameplateUpdate.java
Normal 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);
|
||||
}
|
||||
}
|
||||
27
src/com/hypixel/hytale/protocol/NetworkChannel.java
Normal file
27
src/com/hypixel/hytale/protocol/NetworkChannel.java
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
51
src/com/hypixel/hytale/protocol/NewSpawnUpdate.java
Normal file
51
src/com/hypixel/hytale/protocol/NewSpawnUpdate.java
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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
116
src/com/hypixel/hytale/protocol/PlayerSkinUpdate.java
Normal file
116
src/com/hypixel/hytale/protocol/PlayerSkinUpdate.java
Normal 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);
|
||||
}
|
||||
}
|
||||
76
src/com/hypixel/hytale/protocol/PredictionUpdate.java
Normal file
76
src/com/hypixel/hytale/protocol/PredictionUpdate.java
Normal 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);
|
||||
}
|
||||
}
|
||||
51
src/com/hypixel/hytale/protocol/PropUpdate.java
Normal file
51
src/com/hypixel/hytale/protocol/PropUpdate.java
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
73
src/com/hypixel/hytale/protocol/RepulsionUpdate.java
Normal file
73
src/com/hypixel/hytale/protocol/RepulsionUpdate.java
Normal 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);
|
||||
}
|
||||
}
|
||||
51
src/com/hypixel/hytale/protocol/RespondToHitUpdate.java
Normal file
51
src/com/hypixel/hytale/protocol/RespondToHitUpdate.java
Normal 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;
|
||||
}
|
||||
}
|
||||
4
src/com/hypixel/hytale/protocol/ToClientPacket.java
Normal file
4
src/com/hypixel/hytale/protocol/ToClientPacket.java
Normal file
@@ -0,0 +1,4 @@
|
||||
package com.hypixel.hytale.protocol;
|
||||
|
||||
public interface ToClientPacket extends Packet {
|
||||
}
|
||||
4
src/com/hypixel/hytale/protocol/ToServerPacket.java
Normal file
4
src/com/hypixel/hytale/protocol/ToServerPacket.java
Normal file
@@ -0,0 +1,4 @@
|
||||
package com.hypixel.hytale.protocol;
|
||||
|
||||
public interface ToServerPacket extends Packet {
|
||||
}
|
||||
74
src/com/hypixel/hytale/protocol/TransformUpdate.java
Normal file
74
src/com/hypixel/hytale/protocol/TransformUpdate.java
Normal 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);
|
||||
}
|
||||
}
|
||||
124
src/com/hypixel/hytale/protocol/UIComponentsUpdate.java
Normal file
124
src/com/hypixel/hytale/protocol/UIComponentsUpdate.java
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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() {
|
||||
}
|
||||
|
||||
|
||||
@@ -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() {
|
||||
}
|
||||
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user