9
0
mirror of https://github.com/Xiao-MoMi/craft-engine.git synced 2025-12-24 01:19:24 +00:00

Merge pull request #5 from jhqwqmc/main

feat(bukkit): 添加事件
This commit is contained in:
XiaoMoMi
2025-02-13 04:10:45 +08:00
committed by GitHub
22 changed files with 340 additions and 11 deletions

View File

@@ -0,0 +1,35 @@
package net.momirealms.craftengine.bukkit.api.event;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import org.jetbrains.annotations.NotNull;
import java.nio.file.Path;
public class AsyncGenerateResourcePackEvent extends Event {
private static final HandlerList handlerList = new HandlerList();
private final Path generatedPackPath;
private final Path zipFile;
public AsyncGenerateResourcePackEvent(@NotNull Path generatedPackPath, @NotNull Path zipFile) {
super(true);
this.generatedPackPath = generatedPackPath;
this.zipFile = zipFile;
}
public @NotNull Path generatedPackPath() {
return generatedPackPath;
}
public @NotNull Path zipFile() {
return zipFile;
}
public static HandlerList getHandlerList() {
return handlerList;
}
public @NotNull HandlerList getHandlers() {
return getHandlerList();
}
}

View File

@@ -0,0 +1,12 @@
package net.momirealms.craftengine.bukkit.api.event;
import net.momirealms.craftengine.core.block.ImmutableBlockState;
import org.bukkit.Location;
import org.bukkit.entity.Player;
public class CustomBlockBreakEvent extends CustomBlockEvent {
public CustomBlockBreakEvent(ImmutableBlockState state, Location location, Player player) {
super(state, location, player);
}
}

View File

@@ -0,0 +1,63 @@
package net.momirealms.craftengine.bukkit.api.event;
import net.momirealms.craftengine.core.block.CustomBlock;
import net.momirealms.craftengine.core.block.ImmutableBlockState;
import net.momirealms.craftengine.core.world.BlockPos;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import org.jetbrains.annotations.NotNull;
public abstract class CustomBlockEvent extends Event implements Cancellable {
private static final HandlerList handlerList = new HandlerList();
private boolean cancelled;
private final CustomBlock block;
private final ImmutableBlockState state;
private final Location location;
private final Player player;
public CustomBlockEvent(@NotNull ImmutableBlockState state, @NotNull Location location, @NotNull Player player) {
this.block = state.owner().value();
this.state = state;
this.location = location;
this.player = player;
}
public CustomBlock block() {
return this.block;
}
public BlockPos blockPos() {
return new BlockPos(this.location.getBlockX(), this.location.getBlockY(), this.location.getBlockZ());
}
public Location location() {
return this.location;
}
public @NotNull Player player() {
return this.player;
}
public ImmutableBlockState state() {
return this.state;
}
public static HandlerList getHandlerList() {
return handlerList;
}
public @NotNull HandlerList getHandlers() {
return getHandlerList();
}
public boolean isCancelled() {
return this.cancelled;
}
public void setCancelled(boolean cancel) {
this.cancelled = cancel;
}
}

View File

@@ -0,0 +1,11 @@
package net.momirealms.craftengine.bukkit.api.event;
import net.momirealms.craftengine.core.block.ImmutableBlockState;
import org.bukkit.Location;
import org.bukkit.entity.Player;
public class CustomBlockInteractEvent extends CustomBlockEvent {
public CustomBlockInteractEvent(ImmutableBlockState state, Location location, Player player) {
super(state, location, player);
}
}

View File

@@ -0,0 +1,11 @@
package net.momirealms.craftengine.bukkit.api.event;
import net.momirealms.craftengine.core.block.ImmutableBlockState;
import org.bukkit.Location;
import org.bukkit.entity.Player;
public class CustomBlockPlaceEvent extends CustomBlockEvent {
public CustomBlockPlaceEvent(ImmutableBlockState state, Location location, Player player) {
super(state, location, player);
}
}

View File

@@ -0,0 +1,10 @@
package net.momirealms.craftengine.bukkit.api.event;
import net.momirealms.craftengine.bukkit.entity.furniture.LoadedFurniture;
import org.bukkit.entity.Player;
public class FurnitureBreakEvent extends FurnitureEvent {
public FurnitureBreakEvent(LoadedFurniture furniture, Player player) {
super(furniture, player);
}
}

View File

@@ -0,0 +1,45 @@
package net.momirealms.craftengine.bukkit.api.event;
import net.momirealms.craftengine.bukkit.entity.furniture.LoadedFurniture;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public abstract class FurnitureEvent extends Event implements Cancellable {
private static final HandlerList handlerList = new HandlerList();
private boolean cancelled;
private final LoadedFurniture furniture;
private final Player player;
public FurnitureEvent(@Nullable LoadedFurniture furniture, @NotNull Player player) {
this.furniture = furniture;
this.player = player;
}
public @Nullable LoadedFurniture furniture() {
return this.furniture;
}
public @NotNull Player player() {
return this.player;
}
public static HandlerList getHandlerList() {
return handlerList;
}
public @NotNull HandlerList getHandlers() {
return getHandlerList();
}
public boolean isCancelled() {
return this.cancelled;
}
public void setCancelled(boolean cancel) {
this.cancelled = cancel;
}
}

View File

@@ -0,0 +1,10 @@
package net.momirealms.craftengine.bukkit.api.event;
import net.momirealms.craftengine.bukkit.entity.furniture.LoadedFurniture;
import org.bukkit.entity.Player;
public class FurnitureInteractEvent extends FurnitureEvent {
public FurnitureInteractEvent(LoadedFurniture furniture, Player player) {
super(furniture, player);
}
}

View File

@@ -0,0 +1,12 @@
package net.momirealms.craftengine.bukkit.api.event;
import net.momirealms.craftengine.bukkit.entity.furniture.LoadedFurniture;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class FurniturePlaceEndEvent extends FurnitureEvent {
public FurniturePlaceEndEvent(@Nullable LoadedFurniture furniture, @NotNull Player player) {
super(furniture, player);
}
}

View File

@@ -0,0 +1,10 @@
package net.momirealms.craftengine.bukkit.api.event;
import net.momirealms.craftengine.bukkit.entity.furniture.LoadedFurniture;
import org.bukkit.entity.Player;
public class FurniturePlaceEvent extends FurnitureEvent {
public FurniturePlaceEvent(LoadedFurniture furniture, Player player) {
super(furniture, player);
}
}

View File

@@ -1,13 +1,12 @@
package net.momirealms.craftengine.bukkit.block;
import net.momirealms.craftengine.bukkit.api.event.CustomBlockBreakEvent;
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer;
import net.momirealms.craftengine.bukkit.util.BlockStateUtils;
import net.momirealms.craftengine.bukkit.util.EntityUtils;
import net.momirealms.craftengine.bukkit.util.NoteBlockChainUpdateUtils;
import net.momirealms.craftengine.bukkit.util.Reflections;
import net.momirealms.craftengine.bukkit.util.*;
import net.momirealms.craftengine.bukkit.world.BukkitWorld;
import net.momirealms.craftengine.bukkit.world.BukkitWorldManager;
import net.momirealms.craftengine.core.block.BreakReason;
import net.momirealms.craftengine.core.block.EmptyBlock;
import net.momirealms.craftengine.core.block.ImmutableBlockState;
import net.momirealms.craftengine.core.block.PushReaction;
@@ -16,6 +15,7 @@ import net.momirealms.craftengine.core.entity.player.InteractionHand;
import net.momirealms.craftengine.core.item.Item;
import net.momirealms.craftengine.core.item.ItemKeys;
import net.momirealms.craftengine.core.loot.parameter.LootParameters;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.plugin.config.ConfigManager;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.context.ContextHolder;
@@ -93,7 +93,7 @@ public class BlockEventListener implements Listener {
}
}
@EventHandler(ignoreCancelled = true)
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onPlayerBreak(BlockBreakEvent event) {
org.bukkit.block.Block block = event.getBlock();
Object blockState = BlockStateUtils.blockDataToBlockState(block.getBlockData());
@@ -102,6 +102,9 @@ public class BlockEventListener implements Listener {
ImmutableBlockState state = manager.getImmutableBlockStateUnsafe(stateId);
if (!state.isEmpty()) {
Location location = block.getLocation();
CustomBlockBreakEvent customBreakEvent = new CustomBlockBreakEvent(state, location, event.getPlayer());
boolean isCancelled = EventUtils.fireAndCheckCancel(customBreakEvent);
if (isCancelled) event.setCancelled(true);
net.momirealms.craftengine.core.world.World world = new BukkitWorld(location.getWorld());
// handle waterlogged blocks
@SuppressWarnings("unchecked")
@@ -129,6 +132,7 @@ public class BlockEventListener implements Listener {
return;
}
// drop items
if (isCancelled) return;
ContextHolder.Builder builder = ContextHolder.builder();
builder.withParameter(LootParameters.LOCATION, vec3d);
builder.withParameter(LootParameters.PLAYER, plugin.adapt(player));

View File

@@ -284,4 +284,8 @@ public class LoadedFurniture {
this.addSeatEntity(seatEntity);
seatEntity.addPassenger(player);
}
public Key furnitureId() {
return id;
}
}

View File

@@ -3,6 +3,7 @@ package net.momirealms.craftengine.bukkit.item;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.momirealms.craftengine.bukkit.api.CraftEngineBlocks;
import net.momirealms.craftengine.bukkit.api.event.CustomBlockInteractEvent;
import net.momirealms.craftengine.bukkit.block.BukkitBlockManager;
import net.momirealms.craftengine.bukkit.item.behavior.BlockItemBehavior;
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
@@ -56,6 +57,7 @@ public class ItemEventListener implements Listener {
Location interactionPoint = event.getInteractionPoint();
if (interactionPoint == null) return;
Player bukkitPlayer = event.getPlayer();
Block clickedBlock = Objects.requireNonNull(event.getClickedBlock());
BukkitServerPlayer player = this.plugin.adapt(bukkitPlayer);
InteractionHand hand = event.getHand() == EquipmentSlot.HAND ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND;
if (hand == InteractionHand.OFF_HAND) {
@@ -64,13 +66,27 @@ public class ItemEventListener implements Listener {
event.setCancelled(true);
return;
}
} else {
Key blockKey = BlockStateUtils.getRealBlockId(clickedBlock);
if (blockKey.namespace().equals("craftengine")) {
int blockId = BlockStateUtils.blockDataToId(clickedBlock.getBlockData());
ImmutableBlockState state = BukkitBlockManager.instance().getImmutableBlockState(blockId);
CustomBlockInteractEvent customBlockInteractEvent = new CustomBlockInteractEvent(
state,
clickedBlock.getLocation(),
bukkitPlayer
);
if (EventUtils.fireAndCheckCancel(customBlockInteractEvent)) {
event.setCancelled(true);
return;
}
}
}
Item<ItemStack> itemInHand = player.getItemInHand(hand);
if (itemInHand == null) return;
Optional<CustomItem<ItemStack>> customItem = itemInHand.getCustomItem();
Block clickedBlock = Objects.requireNonNull(event.getClickedBlock());
Material material = itemInHand.getItem().getType();
// is custom item
if (customItem.isPresent()) {

View File

@@ -1,7 +1,9 @@
package net.momirealms.craftengine.bukkit.item.behavior;
import net.momirealms.craftengine.bukkit.api.CraftEngineBlocks;
import net.momirealms.craftengine.bukkit.api.event.CustomBlockPlaceEvent;
import net.momirealms.craftengine.bukkit.block.BukkitBlockManager;
import net.momirealms.craftengine.bukkit.util.EventUtils;
import net.momirealms.craftengine.bukkit.util.LocationUtils;
import net.momirealms.craftengine.bukkit.util.Reflections;
import net.momirealms.craftengine.core.block.CustomBlock;
@@ -69,6 +71,14 @@ public class BlockItemBehavior extends ItemBehavior {
BlockPos pos = placeContext.getClickedPos();
World world = (World) placeContext.getLevel().getHandle();
CustomBlockPlaceEvent customBlockPlaceEvent = new CustomBlockPlaceEvent(
blockStateToPlace,
new Location(world, pos.x(), pos.y(), pos.z()),
(org.bukkit.entity.Player) placeContext.getPlayer().platformPlayer()
);
if (EventUtils.fireAndCheckCancel(customBlockPlaceEvent)) {
return InteractionResult.FAIL;
}
CraftEngineBlocks.place(new Location(world, pos.x(), pos.y(), pos.z()), blockStateToPlace, UpdateOption.UPDATE_ALL_IMMEDIATE);
if (!player.isCreativeMode()) {

View File

@@ -1,7 +1,11 @@
package net.momirealms.craftengine.bukkit.item.behavior;
import net.momirealms.craftengine.bukkit.api.event.FurniturePlaceEndEvent;
import net.momirealms.craftengine.bukkit.api.event.FurniturePlaceEvent;
import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurnitureManager;
import net.momirealms.craftengine.bukkit.entity.furniture.LoadedFurniture;
import net.momirealms.craftengine.bukkit.util.EntityUtils;
import net.momirealms.craftengine.bukkit.util.EventUtils;
import net.momirealms.craftengine.core.block.BlockSounds;
import net.momirealms.craftengine.core.entity.furniture.*;
import net.momirealms.craftengine.core.entity.player.InteractionResult;
@@ -16,6 +20,7 @@ import net.momirealms.craftengine.core.util.*;
import net.momirealms.craftengine.core.world.Vec3d;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.ItemDisplay;
import org.bukkit.inventory.ItemStack;
@@ -23,6 +28,7 @@ import org.bukkit.persistence.PersistentDataType;
import org.bukkit.util.Transformation;
import org.jetbrains.annotations.Nullable;
import org.joml.Quaternionf;
import org.joml.Vector3d;
import org.joml.Vector3f;
import java.util.*;
@@ -82,6 +88,13 @@ public class FurnitureItemBehavior extends ItemBehavior {
if (!player.updateLastSuccessfulInteractionTick(gameTicks)) {
return InteractionResult.FAIL;
}
FurniturePlaceEvent furniturePlaceEvent = new FurniturePlaceEvent(
null,
(org.bukkit.entity.Player) player.platformPlayer()
);
if (EventUtils.fireAndCheckCancel(furniturePlaceEvent)) {
return InteractionResult.FAIL;
}
if (!player.isCreativeMode()) {
Item<?> item = context.getItem();
item.count(item.count() - 1);
@@ -111,9 +124,9 @@ public class FurnitureItemBehavior extends ItemBehavior {
}
// spawn entity and load
EntityUtils.spawnEntity(world, new Location(world, finalPlacePosition.x(), finalPlacePosition.y(), finalPlacePosition.z()), EntityType.ITEM_DISPLAY, entity -> {
Quaternionf quaternion = QuaternionUtils.toQuaternionf(0, Math.toRadians(furnitureYaw), 0);
Entity furnitureEntity = EntityUtils.spawnEntity(world, new Location(world, finalPlacePosition.x(), finalPlacePosition.y(), finalPlacePosition.z()), EntityType.ITEM_DISPLAY, entity -> {
ItemDisplay display = (ItemDisplay) entity;
Quaternionf quaternion = QuaternionUtils.toQuaternionf(0, Math.toRadians(furnitureYaw), 0);
display.setTransformation(
new Transformation(
new Vector3f(),
@@ -127,6 +140,20 @@ public class FurnitureItemBehavior extends ItemBehavior {
BukkitFurnitureManager.instance().handleEntityLoadEarly(display);
});
context.getLevel().playBlockSound(clickedPosition, sounds.placeSound(), 1f, 1f);
FurniturePlaceEndEvent furniturePlaceEndEvent = new FurniturePlaceEndEvent(
new LoadedFurniture(id,
furnitureEntity,
this,
anchorType,
new Vector3d(finalPlacePosition.x(), finalPlacePosition.y(), finalPlacePosition.z()),
quaternion
),
(org.bukkit.entity.Player) player.platformPlayer()
);
if (EventUtils.fireAndCheckCancel(furniturePlaceEndEvent)) {
furnitureEntity.remove();
return InteractionResult.FAIL;
}
return InteractionResult.SUCCESS;
}

View File

@@ -0,0 +1,16 @@
package net.momirealms.craftengine.bukkit.platform;
import net.momirealms.craftengine.bukkit.api.event.AsyncGenerateResourcePackEvent;
import net.momirealms.craftengine.bukkit.util.EventUtils;
import net.momirealms.craftengine.core.platform.Platform;
import java.nio.file.Path;
public class BukkitPlatform implements Platform {
@Override
public void asyncGenerateResourcePackEvent(Path generatedPackPath, Path zipFile) {
AsyncGenerateResourcePackEvent endEvent = new AsyncGenerateResourcePackEvent(generatedPackPath, zipFile);
EventUtils.fireAndForget(endEvent);
}
}

View File

@@ -1,5 +1,6 @@
package net.momirealms.craftengine.bukkit.plugin;
import net.momirealms.craftengine.bukkit.platform.BukkitPlatform;
import net.momirealms.craftengine.bukkit.block.BukkitBlockManager;
import net.momirealms.craftengine.bukkit.block.behavior.BukkitBlockBehaviors;
import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurnitureManager;
@@ -117,6 +118,7 @@ public class BukkitCraftEngine extends CraftEngine {
}
BukkitBlockBehaviors.init();
BukkitItemBehaviors.init();
super.platform = new BukkitPlatform();
super.senderFactory = new BukkitSenderFactory(this);
super.itemManager = new BukkitItemManager(this);
super.recipeManager = new BukkitRecipeManager(this);

View File

@@ -3,6 +3,8 @@ package net.momirealms.craftengine.bukkit.plugin.network;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import it.unimi.dsi.fastutil.ints.IntList;
import net.momirealms.craftengine.bukkit.api.event.FurnitureBreakEvent;
import net.momirealms.craftengine.bukkit.api.event.FurnitureInteractEvent;
import net.momirealms.craftengine.bukkit.block.BukkitBlockManager;
import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurnitureManager;
import net.momirealms.craftengine.bukkit.entity.furniture.LoadedFurniture;
@@ -552,12 +554,16 @@ public class PacketConsumers {
BukkitCraftEngine.instance().scheduler().sync().run(() -> {
if (actionType == Reflections.instance$ServerboundInteractPacket$ActionType$ATTACK) {
if (furniture.isValid()) {
FurnitureBreakEvent furnitureBreakEvent = new FurnitureBreakEvent(furniture, serverPlayer.platformPlayer());
if (EventUtils.fireAndCheckCancel(furnitureBreakEvent)) return;
furniture.onPlayerDestroy(serverPlayer);
}
} else if (actionType == Reflections.instance$ServerboundInteractPacket$ActionType$INTERACT_AT) {
if (player.isSneaking()) {
return;
}
FurnitureInteractEvent furnitureInteractEvent = new FurnitureInteractEvent(furniture, serverPlayer.platformPlayer());
if (EventUtils.fireAndCheckCancel(furnitureInteractEvent)) return;
furniture.getAvailableSeat(entityId).ifPresent(seatPos -> {
if (furniture.occupySeat(seatPos)) {
furniture.mountSeat(Objects.requireNonNull(player.getPlayer()), seatPos);

View File

@@ -35,8 +35,17 @@ public class BlockStateUtils {
public static Key getRealBlockId(Block block) {
BlockData data = block.getBlockData();
Object blockState = blockDataToBlockState(data);
return getRealBlockIdFromState(blockState);
}
public static Key getRealBlockIdFromStateId(int stateId) {
Object blockState = idToBlockState(stateId);
Object owner = getBlockOwner(blockState);
String id = owner.toString();
return getRealBlockIdFromState(owner);
}
public static Key getRealBlockIdFromState(Object blockState) {
String id = blockState.toString();
int first = id.indexOf('{');
int last = id.indexOf('}');
if (first != -1 && last != -1 && last > first) {

View File

@@ -11,6 +11,7 @@ import net.momirealms.craftengine.core.font.Font;
import net.momirealms.craftengine.core.pack.generator.ModelGeneration;
import net.momirealms.craftengine.core.pack.generator.ModelGenerator;
import net.momirealms.craftengine.core.pack.model.ItemModel;
import net.momirealms.craftengine.core.platform.Platform;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.plugin.PluginProperties;
import net.momirealms.craftengine.core.plugin.config.ConfigManager;
@@ -35,12 +36,14 @@ public class PackManagerImpl implements PackManager {
private static final String LEGACY_TEMPLATES = PluginProperties.getValue("legacy-templates").replace(".", "_");
private static final String LATEST_TEMPLATES = PluginProperties.getValue("latest-templates").replace(".", "_");
private final CraftEngine plugin;
private final Platform platform;
private final Map<String, Pack> loadedPacks = new HashMap<>();
private final Map<String, ConfigSectionParser> sectionParsers = new HashMap<>();
private final TreeMap<ConfigSectionParser, List<CachedConfig>> cachedConfigs = new TreeMap<>();
public PackManagerImpl(CraftEngine plugin) {
public PackManagerImpl(CraftEngine plugin, Platform platform) {
this.plugin = plugin;
this.platform = platform;
}
@Override
@@ -267,6 +270,7 @@ public class PackManagerImpl implements PackManager {
Path zipFile = plugin.dataFolderPath()
.resolve("generated")
.resolve("resource_pack.zip");
try {
ZipUtils.zipDirectory(generatedPackPath, zipFile);
} catch (IOException e) {
@@ -275,6 +279,8 @@ public class PackManagerImpl implements PackManager {
long end = System.currentTimeMillis();
plugin.logger().info("Finished generating resource pack in " + (end - start) + "ms");
platform.asyncGenerateResourcePackEvent(generatedPackPath, zipFile);
}
private void generateSounds(Path generatedPackPath) {

View File

@@ -0,0 +1,8 @@
package net.momirealms.craftengine.core.platform;
import java.nio.file.Path;
public interface Platform {
void asyncGenerateResourcePackEvent(Path generatedPackPath, Path zipFile);
}

View File

@@ -8,6 +8,7 @@ import net.momirealms.craftengine.core.item.ItemManager;
import net.momirealms.craftengine.core.item.recipe.RecipeManager;
import net.momirealms.craftengine.core.pack.PackManager;
import net.momirealms.craftengine.core.pack.PackManagerImpl;
import net.momirealms.craftengine.core.platform.Platform;
import net.momirealms.craftengine.core.plugin.classpath.ClassPathAppender;
import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager;
import net.momirealms.craftengine.core.plugin.command.sender.SenderFactory;
@@ -34,6 +35,7 @@ public abstract class CraftEngine implements Plugin {
public static final String MOD_CLASS = "net.momirealms.craftengine.mod.CraftEnginePlugin";
public static final String NAMESPACE = "craftengine";
private static CraftEngine instance;
protected Platform platform;
protected DependencyManager dependencyManager;
protected SchedulerAdapter<?> scheduler;
protected NetworkManager networkManager;
@@ -99,7 +101,7 @@ public abstract class CraftEngine implements Plugin {
@Override
public void enable() {
this.networkManager.enable();
this.packManager = new PackManagerImpl(this);
this.packManager = new PackManagerImpl(this, this.platform);
this.fontManager = new FontManagerImpl(this);
this.templateManager = new TemplateManagerImpl(this);
this.commandManager.registerDefaultFeatures();