diff --git a/common/src/main/java/io/github/amerebagatelle/mods/nuit/NuitClient.java b/common/src/main/java/io/github/amerebagatelle/mods/nuit/NuitClient.java index 24d38ff2..e6c81400 100644 --- a/common/src/main/java/io/github/amerebagatelle/mods/nuit/NuitClient.java +++ b/common/src/main/java/io/github/amerebagatelle/mods/nuit/NuitClient.java @@ -2,6 +2,7 @@ import io.github.amerebagatelle.mods.nuit.api.NuitPlatformHelper; import io.github.amerebagatelle.mods.nuit.config.NuitConfig; +import io.github.amerebagatelle.mods.nuit.resource.SkyboxResourceListener; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -10,6 +11,7 @@ public class NuitClient { private static Logger LOGGER; private static NuitConfig CONFIG; + private static final SkyboxResourceListener skyboxResourceListener = new SkyboxResourceListener(); public static void init() { SkyboxManager.getInstance().setEnabled(config().generalSettings.enable); @@ -30,6 +32,10 @@ public static NuitConfig config() { return CONFIG; } + public static SkyboxResourceListener skyboxResourceListener() { + return skyboxResourceListener; + } + private static NuitConfig loadConfig() { return NuitConfig.load(NuitPlatformHelper.INSTANCE.getConfigDir().resolve("nuit-config.json").toFile()); } diff --git a/common/src/main/java/io/github/amerebagatelle/mods/nuit/SkyboxManager.java b/common/src/main/java/io/github/amerebagatelle/mods/nuit/SkyboxManager.java index 7234c842..3278ff0f 100644 --- a/common/src/main/java/io/github/amerebagatelle/mods/nuit/SkyboxManager.java +++ b/common/src/main/java/io/github/amerebagatelle/mods/nuit/SkyboxManager.java @@ -11,10 +11,13 @@ import io.github.amerebagatelle.mods.nuit.components.Metadata; import io.github.amerebagatelle.mods.nuit.mixin.LevelRendererAccessor; import io.github.amerebagatelle.mods.nuit.skybox.DefaultHandler; +import io.github.amerebagatelle.mods.nuit.skybox.TextureRegistrar; import io.github.amerebagatelle.mods.nuit.skybox.SkyboxType; import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap; import net.minecraft.client.Camera; +import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.client.renderer.texture.SimpleTexture; import net.minecraft.resources.ResourceLocation; import org.jetbrains.annotations.ApiStatus.Internal; import org.joml.Matrix4f; @@ -23,6 +26,7 @@ public class SkyboxManager implements NuitApi { private static final SkyboxManager INSTANCE = new SkyboxManager(); + private final List preloadedTextures = new ArrayList<>(); private final Map skyboxMap = new Object2ObjectLinkedOpenHashMap<>(); /** * Stores a list of permanent skyboxes @@ -65,7 +69,7 @@ public static SkyboxManager getInstance() { } public void addSkybox(ResourceLocation identifier, JsonObject jsonObject) { - var skybox = SkyboxManager.parseSkyboxJson(identifier, jsonObject); + Optional skybox = SkyboxManager.parseSkyboxJson(identifier, jsonObject); if (skybox.isPresent()) { NuitClient.getLogger().info("Adding skybox {}", identifier.toString()); this.addSkybox(identifier, skybox.get()); @@ -76,6 +80,14 @@ public void addSkybox(ResourceLocation identifier, Skybox skybox) { Preconditions.checkNotNull(identifier, "Identifier was null"); Preconditions.checkNotNull(skybox, "Skybox was null"); DefaultHandler.addConditions(skybox); + + if (skybox instanceof TextureRegistrar textureRegistrar) { + textureRegistrar.getTexturesToRegister().forEach(resourceLocation -> { + Minecraft.getInstance().getTextureManager().register(resourceLocation, new SimpleTexture(resourceLocation)); + this.preloadedTextures.add(resourceLocation); + }); + } + this.skyboxMap.put(identifier, skybox); } @@ -98,6 +110,8 @@ public void clearSkyboxes() { DefaultHandler.clearConditionsExcept(this.permanentSkyboxMap.values()); this.skyboxMap.clear(); this.activeSkyboxes.clear(); + this.preloadedTextures.forEach(texture -> Minecraft.getInstance().getTextureManager().release(texture)); + this.preloadedTextures.clear(); } @Internal diff --git a/common/src/main/java/io/github/amerebagatelle/mods/nuit/resource/SkyboxResourceListener.java b/common/src/main/java/io/github/amerebagatelle/mods/nuit/resource/SkyboxResourceListener.java index 979632a4..09dca29d 100644 --- a/common/src/main/java/io/github/amerebagatelle/mods/nuit/resource/SkyboxResourceListener.java +++ b/common/src/main/java/io/github/amerebagatelle/mods/nuit/resource/SkyboxResourceListener.java @@ -6,16 +6,21 @@ import io.github.amerebagatelle.mods.nuit.NuitClient; import io.github.amerebagatelle.mods.nuit.api.NuitApi; import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.packs.resources.PreparableReloadListener; import net.minecraft.server.packs.resources.Resource; import net.minecraft.server.packs.resources.ResourceManager; +import net.minecraft.util.profiling.ProfilerFiller; +import org.jetbrains.annotations.NotNull; import java.io.InputStreamReader; import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; -public class SkyboxResourceListener { +public class SkyboxResourceListener implements PreparableReloadListener { private static final Gson GSON = new GsonBuilder().setPrettyPrinting().serializeNulls().setLenient().create(); - public void readFiles(ResourceManager resourceManager) { + public void readFiles(ResourceManager resourceManager, Executor backgroundExecutor) { NuitApi skyboxManager = NuitApi.getInstance(); skyboxManager.clearSkyboxes(); @@ -31,4 +36,9 @@ public void readFiles(ResourceManager resourceManager) { } }); } + + @Override + public @NotNull CompletableFuture reload(PreparationBarrier preparationBarrier, ResourceManager resourceManager, ProfilerFiller profilerFiller, ProfilerFiller profilerFiller2, Executor executor, Executor executor2) { + return CompletableFuture.runAsync(() -> this.readFiles(resourceManager, executor), executor2).thenCompose(preparationBarrier::wait); + } } diff --git a/common/src/main/java/io/github/amerebagatelle/mods/nuit/skybox/AbstractSkybox.java b/common/src/main/java/io/github/amerebagatelle/mods/nuit/skybox/AbstractSkybox.java index 23626b12..1266e3e1 100644 --- a/common/src/main/java/io/github/amerebagatelle/mods/nuit/skybox/AbstractSkybox.java +++ b/common/src/main/java/io/github/amerebagatelle/mods/nuit/skybox/AbstractSkybox.java @@ -12,6 +12,7 @@ import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.player.LocalPlayer; import net.minecraft.core.registries.Registries; +import net.minecraft.resources.ResourceLocation; import net.minecraft.util.Mth; import net.minecraft.util.Tuple; import net.minecraft.world.effect.MobEffects; @@ -121,8 +122,9 @@ public float updateAlpha() { * @return Whether all conditions were met */ protected boolean checkConditions() { - return this.checkDimensions() && this.checkWorlds() && this.checkBiomes() && this.checkXRanges() && - this.checkYRanges() && this.checkZRanges() && this.checkWeather() && this.checkEffects(); + return this.checkDimensions() && this.checkWorlds() && this.checkBiomes() && + this.checkXRanges() && this.checkYRanges() && this.checkZRanges() && + this.checkWeather() && this.checkEffects(); } /** @@ -130,11 +132,18 @@ protected boolean checkConditions() { */ protected boolean checkBiomes() { Minecraft client = Minecraft.getInstance(); - Objects.requireNonNull(client.level); - Objects.requireNonNull(client.player); - return this.conditions.getBiomes().getEntries().isEmpty() || this.conditions.getBiomes().isExcludes() ^ ( - this.conditions.getBiomes().getEntries().contains(client.level.getBiome(client.player.blockPosition()).unwrapKey().orElseThrow().location()) || - this.conditions.getBiomes().getEntries().contains(DefaultHandler.DEFAULT) && DefaultHandler.checkFallbackBiomes()); + ClientLevel level = Objects.requireNonNull(client.level); + LocalPlayer player = Objects.requireNonNull(client.player); + + if (this.conditions.getBiomes().getEntries().isEmpty()) { + return true; + } + + boolean isExcluded = this.conditions.getBiomes().isExcludes(); + ResourceLocation biomeKey = level.getBiome(player.blockPosition()).unwrapKey().orElseThrow().location(); + boolean isDefault = this.conditions.getBiomes().getEntries().contains(DefaultHandler.DEFAULT); + + return isExcluded ^ (this.conditions.getBiomes().getEntries().contains(biomeKey) || (isDefault && DefaultHandler.checkFallbackBiomes())); } /** @@ -218,26 +227,26 @@ protected boolean checkZRanges() { * @return Whether the current weather is valid for this skybox. */ protected boolean checkWeather() { - ClientLevel world = Objects.requireNonNull(Minecraft.getInstance().level); - LocalPlayer player = Objects.requireNonNull(Minecraft.getInstance().player); - Biome.Precipitation precipitation = world.getBiome(player.blockPosition()).value().getPrecipitationAt(player.blockPosition()); if (this.conditions.getWeathers().getEntries().isEmpty()) { return true; } - if ((this.conditions.getWeathers().isExcludes() ^ this.conditions.getWeathers().getEntries().contains(Weather.THUNDER)) && world.isThundering()) { - return true; - } - if ((this.conditions.getWeathers().isExcludes() ^ this.conditions.getWeathers().getEntries().contains(Weather.RAIN)) && world.isRaining() && !world.isThundering()) { - return true; - } - if ((this.conditions.getWeathers().isExcludes() ^ this.conditions.getWeathers().getEntries().contains(Weather.SNOW)) && world.isRaining() && precipitation == Biome.Precipitation.SNOW) { - return true; - } - if ((this.conditions.getWeathers().isExcludes() ^ this.conditions.getWeathers().getEntries().contains(Weather.BIOME_RAIN)) && world.isRaining() && precipitation == Biome.Precipitation.RAIN) { - return true; - } - return (this.conditions.getWeathers().isExcludes() ^ this.conditions.getWeathers().getEntries().contains(Weather.CLEAR)) && !world.isRaining() && !world.isThundering(); + ClientLevel world = Objects.requireNonNull(Minecraft.getInstance().level); + LocalPlayer player = Objects.requireNonNull(Minecraft.getInstance().player); + Biome.Precipitation precipitation = world.getBiome(player.blockPosition()).value().getPrecipitationAt(player.blockPosition()); + + boolean isExcluded = this.conditions.getWeathers().isExcludes(); + boolean isThundering = world.isThundering(); + boolean isRaining = world.isRaining(); + boolean isSnowing = isRaining && precipitation == Biome.Precipitation.SNOW; + boolean isBiomeRaining = isRaining && precipitation == Biome.Precipitation.RAIN; + boolean isClear = !isRaining && !isThundering; + + return (isExcluded ^ this.conditions.getWeathers().getEntries().contains(Weather.THUNDER) && isThundering) || + (isExcluded ^ this.conditions.getWeathers().getEntries().contains(Weather.RAIN) && isRaining && !isThundering) || + (isExcluded ^ this.conditions.getWeathers().getEntries().contains(Weather.SNOW) && isSnowing) || + (isExcluded ^ this.conditions.getWeathers().getEntries().contains(Weather.BIOME_RAIN) && isBiomeRaining) || + (isExcluded ^ this.conditions.getWeathers().getEntries().contains(Weather.CLEAR) && isClear); } @Override diff --git a/common/src/main/java/io/github/amerebagatelle/mods/nuit/skybox/TextureRegistrar.java b/common/src/main/java/io/github/amerebagatelle/mods/nuit/skybox/TextureRegistrar.java new file mode 100644 index 00000000..109619a9 --- /dev/null +++ b/common/src/main/java/io/github/amerebagatelle/mods/nuit/skybox/TextureRegistrar.java @@ -0,0 +1,9 @@ +package io.github.amerebagatelle.mods.nuit.skybox; + +import net.minecraft.resources.ResourceLocation; + +import java.util.List; + +public interface TextureRegistrar { + List getTexturesToRegister(); +} diff --git a/common/src/main/java/io/github/amerebagatelle/mods/nuit/skybox/textured/MultiTexturedSkybox.java b/common/src/main/java/io/github/amerebagatelle/mods/nuit/skybox/textured/MultiTexturedSkybox.java index f5245176..2e063aa9 100644 --- a/common/src/main/java/io/github/amerebagatelle/mods/nuit/skybox/textured/MultiTexturedSkybox.java +++ b/common/src/main/java/io/github/amerebagatelle/mods/nuit/skybox/textured/MultiTexturedSkybox.java @@ -10,6 +10,7 @@ import io.github.amerebagatelle.mods.nuit.skybox.AbstractSkybox; import io.github.amerebagatelle.mods.nuit.util.Utils; import net.minecraft.client.Camera; +import net.minecraft.resources.ResourceLocation; import org.joml.Matrix4f; import java.util.ArrayList; @@ -89,4 +90,9 @@ public void renderSkybox(LevelRendererAccessor worldRendererAccess, PoseStack ma public List getAnimations() { return this.animatableTextures; } + + @Override + public List getTexturesToRegister() { + return this.animatableTextures.stream().map(texture -> texture.getTexture().getTextureId()).toList(); + } } diff --git a/common/src/main/java/io/github/amerebagatelle/mods/nuit/skybox/textured/SquareTexturedSkybox.java b/common/src/main/java/io/github/amerebagatelle/mods/nuit/skybox/textured/SquareTexturedSkybox.java index ee13be2f..4d9e05d2 100644 --- a/common/src/main/java/io/github/amerebagatelle/mods/nuit/skybox/textured/SquareTexturedSkybox.java +++ b/common/src/main/java/io/github/amerebagatelle/mods/nuit/skybox/textured/SquareTexturedSkybox.java @@ -10,8 +10,11 @@ import io.github.amerebagatelle.mods.nuit.skybox.AbstractSkybox; import io.github.amerebagatelle.mods.nuit.util.Utils; import net.minecraft.client.Camera; +import net.minecraft.resources.ResourceLocation; import org.joml.Matrix4f; +import java.util.List; + public class SquareTexturedSkybox extends TexturedSkybox { public static Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( Properties.CODEC.optionalFieldOf("properties", Properties.of()).forGetter(AbstractSkybox::getProperties), @@ -68,4 +71,9 @@ public void renderSkybox(LevelRendererAccessor worldRendererAccess, PoseStack ma } BufferUploader.drawWithShader(bufferBuilder.buildOrThrow()); } + + @Override + public List getTexturesToRegister() { + return List.of(this.texture.getTextureId()); + } } diff --git a/common/src/main/java/io/github/amerebagatelle/mods/nuit/skybox/textured/TexturedSkybox.java b/common/src/main/java/io/github/amerebagatelle/mods/nuit/skybox/textured/TexturedSkybox.java index 33a25402..def5b4c0 100644 --- a/common/src/main/java/io/github/amerebagatelle/mods/nuit/skybox/textured/TexturedSkybox.java +++ b/common/src/main/java/io/github/amerebagatelle/mods/nuit/skybox/textured/TexturedSkybox.java @@ -9,6 +9,7 @@ import io.github.amerebagatelle.mods.nuit.components.Rotation; import io.github.amerebagatelle.mods.nuit.mixin.LevelRendererAccessor; import io.github.amerebagatelle.mods.nuit.skybox.AbstractSkybox; +import io.github.amerebagatelle.mods.nuit.skybox.TextureRegistrar; import net.minecraft.client.Camera; import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.ClientLevel; @@ -17,7 +18,7 @@ import java.util.Objects; -public abstract class TexturedSkybox extends AbstractSkybox implements RotatableSkybox { +public abstract class TexturedSkybox extends AbstractSkybox implements RotatableSkybox, TextureRegistrar { public Rotation rotation; public Blend blend; diff --git a/common/src/main/java/io/github/amerebagatelle/mods/nuit/util/Utils.java b/common/src/main/java/io/github/amerebagatelle/mods/nuit/util/Utils.java index 93f3db59..88398dde 100644 --- a/common/src/main/java/io/github/amerebagatelle/mods/nuit/util/Utils.java +++ b/common/src/main/java/io/github/amerebagatelle/mods/nuit/util/Utils.java @@ -37,10 +37,16 @@ public class Utils { * @return The output intersection */ public static UVRange mapUVRanges(UVRange input, UVRange output, UVRange inputIntersection) { - float u1 = (inputIntersection.getMinU() - input.getMinU()) / (input.getMaxU() - input.getMinU()) * (output.getMaxU() - output.getMinU()) + output.getMinU(); - float u2 = (inputIntersection.getMaxU() - input.getMinU()) / (input.getMaxU() - input.getMinU()) * (output.getMaxU() - output.getMinU()) + output.getMinU(); - float v1 = (inputIntersection.getMinV() - input.getMinV()) / (input.getMaxV() - input.getMinV()) * (output.getMaxV() - output.getMinV()) + output.getMinV(); - float v2 = (inputIntersection.getMaxV() - input.getMinV()) / (input.getMaxV() - input.getMinV()) * (output.getMaxV() - output.getMinV()) + output.getMinV(); + float inputUWidth = input.getMaxU() - input.getMinU(); + float outputUWidth = output.getMaxU() - output.getMinU(); + float inputVHeight = input.getMaxV() - input.getMinV(); + float outputVHeight = output.getMaxV() - output.getMinV(); + + float u1 = (inputIntersection.getMinU() - input.getMinU()) / inputUWidth * outputUWidth + output.getMinU(); + float u2 = (inputIntersection.getMaxU() - input.getMinU()) / inputUWidth * outputUWidth + output.getMinU(); + float v1 = (inputIntersection.getMinV() - input.getMinV()) / inputVHeight * outputVHeight + output.getMinV(); + float v2 = (inputIntersection.getMaxV() - input.getMinV()) / inputVHeight * outputVHeight + output.getMinV(); + return new UVRange(u1, v1, u2, v2); } @@ -70,8 +76,8 @@ public static UVRange findUVIntersection(UVRange first, UVRange second) { */ public static boolean checkRanges(double value, List minMaxEntries, boolean inverse) { return minMaxEntries.isEmpty() || (inverse ^ minMaxEntries.stream() - .anyMatch(minMaxEntry -> Range.closed(minMaxEntry.min(), minMaxEntry.max()) - .contains((float) value))); + .map(entry -> Range.closed(entry.min(), entry.max())) + .anyMatch(range -> range.contains((float) value))); } /** diff --git a/fabric/src/main/java/io/github/amerebagatelle/mods/nuit/fabric/NuitClientFabric.java b/fabric/src/main/java/io/github/amerebagatelle/mods/nuit/fabric/NuitClientFabric.java index b8dfba3f..55925da0 100644 --- a/fabric/src/main/java/io/github/amerebagatelle/mods/nuit/fabric/NuitClientFabric.java +++ b/fabric/src/main/java/io/github/amerebagatelle/mods/nuit/fabric/NuitClientFabric.java @@ -12,14 +12,21 @@ import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper; import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback; import net.fabricmc.fabric.api.event.registry.FabricRegistryBuilder; +import net.fabricmc.fabric.api.resource.IdentifiableResourceReloadListener; import net.fabricmc.fabric.api.resource.ResourceManagerHelper; import net.fabricmc.fabric.api.resource.SimpleSynchronousResourceReloadListener; +import net.minecraft.client.Minecraft; import net.minecraft.core.MappedRegistry; import net.minecraft.core.Registry; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.packs.PackType; import net.minecraft.server.packs.resources.ResourceManager; +import net.minecraft.util.profiling.ProfilerFiller; +import org.jetbrains.annotations.NotNull; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; public class NuitClientFabric implements ClientModInitializer { public static final Registry> REGISTRY = FabricRegistryBuilder.from(new MappedRegistry<>(SkyboxType.SKYBOX_TYPE_REGISTRY_KEY, Lifecycle.stable())).buildAndRegister(); @@ -27,15 +34,15 @@ public class NuitClientFabric implements ClientModInitializer { @Override public void onInitializeClient() { SkyboxType.register(skyboxType -> Registry.register(REGISTRY, skyboxType.createId(), skyboxType)); - ResourceManagerHelper.get(PackType.CLIENT_RESOURCES).registerReloadListener(new SimpleSynchronousResourceReloadListener() { + ResourceManagerHelper.get(PackType.CLIENT_RESOURCES).registerReloadListener(new IdentifiableResourceReloadListener() { @Override - public ResourceLocation getFabricId() { - return ResourceLocation.tryBuild(NuitClient.MOD_ID, "skybox_reader"); + public @NotNull CompletableFuture reload(PreparationBarrier preparationBarrier, ResourceManager resourceManager, ProfilerFiller profilerFiller, ProfilerFiller profilerFiller2, Executor executor, Executor executor2) { + return NuitClient.skyboxResourceListener().reload(preparationBarrier, resourceManager, profilerFiller, profilerFiller2, executor, executor2); } @Override - public void onResourceManagerReload(ResourceManager resourceManager) { - new SkyboxResourceListener().readFiles(resourceManager); + public ResourceLocation getFabricId() { + return ResourceLocation.tryBuild(NuitClient.MOD_ID, "skybox_reader"); } }); @@ -46,6 +53,5 @@ public void onResourceManagerReload(ResourceManager resourceManager) { KeyBindingHelper.registerKeyBinding(NuitClient.config().getKeyBinding().toggleNuit); KeyBindingHelper.registerKeyBinding(NuitClient.config().getKeyBinding().toggleSkyboxDebugHud); NuitClient.init(); - } } \ No newline at end of file diff --git a/neoforge/src/main/java/io/github/amerebagatelle/mods/nuit/neoforge/NuitNeoForge.java b/neoforge/src/main/java/io/github/amerebagatelle/mods/nuit/neoforge/NuitNeoForge.java index 5f04152e..e93002b4 100644 --- a/neoforge/src/main/java/io/github/amerebagatelle/mods/nuit/neoforge/NuitNeoForge.java +++ b/neoforge/src/main/java/io/github/amerebagatelle/mods/nuit/neoforge/NuitNeoForge.java @@ -3,7 +3,6 @@ import io.github.amerebagatelle.mods.nuit.NuitClient; import io.github.amerebagatelle.mods.nuit.SkyboxManager; import io.github.amerebagatelle.mods.nuit.api.skyboxes.Skybox; -import io.github.amerebagatelle.mods.nuit.resource.SkyboxResourceListener; import io.github.amerebagatelle.mods.nuit.screen.SkyboxDebugScreen; import io.github.amerebagatelle.mods.nuit.skybox.SkyboxType; import net.minecraft.client.Minecraft; @@ -23,8 +22,6 @@ import net.neoforged.neoforge.registries.RegisterEvent; import net.neoforged.neoforge.registries.RegistryBuilder; -import java.util.concurrent.CompletableFuture; - @Mod(NuitClient.MOD_ID) public final class NuitNeoForge { public static final Registry> REGISTRY = new RegistryBuilder<>(SkyboxType.SKYBOX_TYPE_REGISTRY_KEY).create(); @@ -76,6 +73,6 @@ public void registerSkyTypes(RegisterEvent event) { @SubscribeEvent public void registerClientReloadListener(RegisterClientReloadListenersEvent event) { - event.registerReloadListener((pPreparationBarrier, pResourceManager, pPreparationsProfiler, pReloadProfiler, pBackgroundExecutor, pGameExecutor) -> CompletableFuture.runAsync(() -> new SkyboxResourceListener().readFiles(pResourceManager), pGameExecutor).thenCompose(pPreparationBarrier::wait)); + event.registerReloadListener((pPreparationBarrier, pResourceManager, pPreparationsProfiler, pReloadProfiler, pBackgroundExecutor, pGameExecutor) -> NuitClient.skyboxResourceListener().reload(pPreparationBarrier, pResourceManager, pPreparationsProfiler, pReloadProfiler, pBackgroundExecutor, pGameExecutor)); } } \ No newline at end of file