Skip to content

Commit

Permalink
refactor(context): Clarify data flow of context
Browse files Browse the repository at this point in the history
  • Loading branch information
PeyaPeyaPeyang committed Dec 23, 2023
1 parent e23046b commit 43dece8
Show file tree
Hide file tree
Showing 30 changed files with 415 additions and 247 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public static <T extends Entity> T spawnEntity(EntityStructure structure, @Nulla
{
Location spawnLoc = locDef == null ? null: locDef.create();
if (spawnLoc == null)
spawnLoc = engine.getContext().getStage().getSpawnLocation();
spawnLoc = engine.getContext().getStage().getWorld().getSpawnLocation();
// World が指定されていない場合は、ステージのワールドを使う。
spawnLoc = Utils.assignWorldToLocation(spawnLoc, engine);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public boolean isFired(@NotNull Argument argument, @NotNull ScenarioEngine engin

PlayerInteractAtEntityEvent e = (PlayerInteractAtEntityEvent) event;
Vector clickedPosition = e.getClickedPosition();
Location loc = clickedPosition.toLocation(engine.getContext().getStage());
Location loc = clickedPosition.toLocation(engine.getContext().getStage().getWorld());

return argument.getPosition() == null || argument.getPosition().isAdequate(loc);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,14 @@ public class PlayerInteractBlockAction extends AbstractPlayerAction<PlayerIntera

private static Block getClickBlock(ScenarioEngine engine, Argument argument)
{
World world = engine.getManager().getRegistry().getContextManager().getStageManager().getStage();

Location clickPos;
BlockStructure blockStructure = argument.getBlock();
if (!(blockStructure == null || blockStructure.getLocation() == null))
clickPos = blockStructure.getLocation().create().toBlockLocation();
else // 指定がなかったら自身の位置をクリックする(しかない)
clickPos = argument.getTarget(engine).getLocation().toBlockLocation();

World world = engine.getContext().getStage().getWorld();
return world.getBlockAt(clickPos);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ public World getWorld()
public World getWorldNonNull(ScenarioEngine engine)
{
if (this.worldRef == null)
return engine.getManager().getRegistry().getContextManager().getStageManager().getStage();
return engine.getContext().getStage().getWorld();

return this.getWorld();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,12 +84,12 @@ public static List<? extends Entity> getEntities(EntityStructure structure, @Nul
.filter(finalPredicate)
.collect(Collectors.toList());
}
else if (!(context.getEntities() == null || context.getEntities().isEmpty()))
else if (!context.getEntities().isEmpty())
return context.getEntities().stream()
.filter(finalPredicate)
.collect(Collectors.toList());

return context.getStage().getEntities().stream()
return context.getStage().getWorld().getEntities().stream()
.filter(finalPredicate)
.collect(Collectors.toList());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public static Location assignWorldToLocation(@NotNull Location loc, @NotNull Sce
return loc;

Location newLoc = loc.clone();
newLoc.setWorld(engine.getContext().getStage());
newLoc.setWorld(engine.getContext().getStage().getWorld());

return newLoc;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,50 @@
package org.kunlab.scenamatica.context;

import lombok.AccessLevel;
import lombok.Getter;
import lombok.Value;
import org.bukkit.World;
import org.bukkit.entity.Entity;
import org.jetbrains.annotations.NotNull;
import org.kunlab.scenamatica.interfaces.context.Actor;
import org.kunlab.scenamatica.interfaces.context.Context;
import org.kunlab.scenamatica.interfaces.context.ContextManager;
import org.kunlab.scenamatica.interfaces.context.Stage;

import java.util.List;

@Value
public class ContextImpl implements Context
{
World stage;
@Getter(AccessLevel.NONE)
ContextManager manager;

Stage stage;
@NotNull
List<Actor> actors;
List<? extends Actor> actors;
@NotNull
List<Entity> entities;
List<? extends Entity> entities;

@Override
public boolean hasStage()
{
return this.stage != null;
}

@Override
public boolean hasActors()
{
return !this.actors.isEmpty();
}

@Override
public boolean hasEntities()
{
return !this.entities.isEmpty();
}

@Override
public void destroy()
{
this.manager.destroyContext(this);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package org.kunlab.scenamatica.context;

import lombok.AccessLevel;
import lombok.Getter;
import lombok.SneakyThrows;
import net.kunmc.lab.peyangpaperutils.lang.LangProvider;
Expand All @@ -12,18 +11,22 @@
import org.bukkit.entity.EntityType;
import org.bukkit.event.entity.CreatureSpawnEvent;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.kunlab.scenamatica.commons.utils.LogUtils;
import org.kunlab.scenamatica.commons.utils.ThreadingUtil;
import org.kunlab.scenamatica.context.actor.ActorManagerImpl;
import org.kunlab.scenamatica.context.stage.StageManagerImpl;
import org.kunlab.scenamatica.exceptions.context.EntityCreationException;
import org.kunlab.scenamatica.exceptions.context.actor.ActorCreationException;
import org.kunlab.scenamatica.exceptions.context.actor.VersionNotSupportedException;
import org.kunlab.scenamatica.exceptions.context.stage.StageAlreadyDestroyedException;
import org.kunlab.scenamatica.exceptions.context.stage.StageCreateFailedException;
import org.kunlab.scenamatica.exceptions.context.stage.StageNotCreatedException;
import org.kunlab.scenamatica.interfaces.ScenamaticaRegistry;
import org.kunlab.scenamatica.interfaces.context.Actor;
import org.kunlab.scenamatica.interfaces.context.ActorManager;
import org.kunlab.scenamatica.interfaces.context.Context;
import org.kunlab.scenamatica.interfaces.context.ContextManager;
import org.kunlab.scenamatica.interfaces.context.Stage;
import org.kunlab.scenamatica.interfaces.context.StageManager;
import org.kunlab.scenamatica.interfaces.scenariofile.Mapped;
import org.kunlab.scenamatica.interfaces.scenariofile.ScenarioFileStructure;
Expand All @@ -38,7 +41,6 @@
import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;

public class ContextManagerImpl implements ContextManager
{
Expand All @@ -54,23 +56,16 @@ public class ContextManagerImpl implements ContextManager
private final StageManager stageManager;
private final EntityChunkLoader chunkLoader;
private final Logger logger;
@Getter(AccessLevel.PACKAGE)
List<UUID> generatedEntities;
private boolean isWorldPrepared;
private boolean isActorPrepared;

public ContextManagerImpl(@NotNull ScenamaticaRegistry registry) throws VersionNotSupportedException
{
this.registry = registry;
this.verbose = registry.getEnvironment().isVerbose();
this.actorManager = new ActorManagerImpl(registry, this);
this.actorManager = new ActorManagerImpl(registry);
this.stageManager = new StageManagerImpl(registry);
this.logger = registry.getLogger();
this.chunkLoader = new EntityChunkLoader(registry);

this.isWorldPrepared = false;
this.isActorPrepared = false;

// ゴミを残さないように
SpigotConfig.disablePlayerDataSaving = true;
SpigotConfig.userCacheCap = 0;
Expand All @@ -81,7 +76,7 @@ private static MsgArgs getArgs(ScenarioFileStructure scenario, UUID testID)
return MsgArgs.of("prefix", LogUtils.gerScenarioPrefix(testID, scenario));
}

private World prepareWorld(ContextStructure context, ScenarioFileStructure scenario, UUID testID) throws StageCreateFailedException
private Stage prepareStage(ContextStructure context, ScenarioFileStructure scenario, UUID testID) throws StageCreateFailedException
{
if (context == null || context.getWorld() == null)
return this.stageManager.shared(DEFAULT_ORIGINAL_WORLD_NAME);
Expand All @@ -104,35 +99,34 @@ private World prepareWorld(ContextStructure context, ScenarioFileStructure scena
);
}

@NotNull
private List<Actor> prepareActors(ContextStructure context, ScenarioFileStructure scenario, UUID testID) throws StageNotCreatedException
@Nullable
private List<Actor> tryPrepareActors(World defaultWorld, ContextStructure context)
{
List<Actor> actors = new ArrayList<>();
try
{
List<Actor> actors = new ArrayList<>();
for (PlayerStructure actor : context.getActors())
actors.add(this.actorManager.createActor(actor));

this.isActorPrepared = true;
actors.add(this.actorManager.createActor(defaultWorld, actor));

return actors;
}
catch (Exception e)
{
this.registry.getExceptionHandler().report(e);
this.logActorGenFail(scenario, testID);

this.stageManager.destroyStage();
return Collections.emptyList();
for (Actor actor : actors)
this.actorManager.destroyActor(actor);

return null;
}

}

private <T extends Entity> T spawnEntity(World stage, EntityStructure entity)
private <T extends Entity> T spawnEntity(World stage, EntityStructure entity) throws EntityCreationException
{
EntityType type = entity.getType();
if (type == null)
throw new IllegalArgumentException("Unable to spawn entity: type is null");
throw new EntityCreationException("Unable to spawn entity: type is null");

Location spawnLoc;
if (entity.getLocation() == null)
Expand Down Expand Up @@ -166,34 +160,38 @@ private <T extends Entity> T spawnEntity(World stage, EntityStructure entity)
);
}

private List<Entity> prepareEntities(World stage, ContextStructure context, ScenarioFileStructure scenario, UUID testID) throws StageCreateFailedException, StageNotCreatedException
private List<Entity> prepareEntities(Stage stage, ContextStructure context) throws EntityCreationException
{
List<Entity> entities = new ArrayList<>();
for (EntityStructure entity : context.getEntities())
entities.add(this.spawnEntity(stage, entity));

this.isActorPrepared = true;
entities.add(this.spawnEntity(stage.getWorld(), entity));

return entities;
}

@Override
public Context prepareContext(@NotNull ScenarioFileStructure scenario, @NotNull UUID testID)
throws StageNotCreatedException, StageCreateFailedException
throws StageAlreadyDestroyedException, StageCreateFailedException, ActorCreationException, EntityCreationException
{
ContextStructure context = scenario.getContext();

this.logIfVerbose(scenario, "context.creating", testID);

this.logIfVerbose(scenario, "context.stage.generating", testID);
World stage = this.prepareWorld(context, scenario, testID);
this.isWorldPrepared = true;
Stage stage = this.prepareStage(context, scenario, testID);

List<Actor> actors;
if (!(context == null || context.getActors().isEmpty()))
{
this.logIfVerbose(scenario, "context.actor.generating", testID);
actors = this.prepareActors(context, scenario, testID);
actors = this.tryPrepareActors(stage.getWorld(), context);
if (actors == null)
{
this.logActorGenFail(scenario, testID);
// 失敗したのでロールバック
stage.destroy();
throw new ActorCreationException();
}
}
else
actors = Collections.emptyList();
Expand All @@ -202,18 +200,19 @@ public Context prepareContext(@NotNull ScenarioFileStructure scenario, @NotNull
if (!(context == null || context.getEntities().isEmpty()))
{
this.logIfVerbose(scenario, "context.entity.generating", testID);
generatedEntities = this.prepareEntities(stage, context, scenario, testID);

this.generatedEntities = generatedEntities.stream()
.map(Entity::getUniqueId)
.collect(Collectors.toList());
generatedEntities = this.prepareEntities(stage, context);
}
else
generatedEntities = Collections.emptyList();


this.logIfVerbose(scenario, "context.created", testID);
return new ContextImpl(stage, actors, generatedEntities);
return new ContextImpl(
this,
stage,
Collections.unmodifiableList(actors),
Collections.unmodifiableList(generatedEntities)
);
}

private void logIfVerbose(ScenarioFileStructure scenario, String message, MsgArgs args, UUID testID)
Expand All @@ -235,45 +234,37 @@ private void logActorGenFail(ScenarioFileStructure scenario, UUID testID)
this.logger.log(Level.WARNING, LangProvider.get("context.actor.failed", getArgs(scenario, testID)));
}

@SneakyThrows(StageNotCreatedException.class)
@Override
public void destroyContext()
@SneakyThrows(StageAlreadyDestroyedException.class)
public void destroyContext(Context context)
{
if (this.isWorldPrepared)
this.stageManager.destroyStage(); // StageNotCreatedException はチェック済み。
if (context.hasStage())
this.stageManager.destroyStage(context.getStage()); // StageNotCreatedException はチェック済み。

if (this.isActorPrepared)
if (context.hasActors())
{
List<Actor> actors = new ArrayList<>(this.actorManager.getActors()); // ConcurrentModificationException 対策
List<Actor> actors = new ArrayList<>(context.getActors()); // ConcurrentModificationException 対策
for (Actor actor : actors)
this.actorManager.destroyActor(actor);
}

this.chunkLoader.clear();
if (this.generatedEntities != null)
if (context.hasEntities())
{
for (UUID uuid : this.generatedEntities)
{
Entity entity = Bukkit.getEntity(uuid);
for (Entity entity : context.getEntities())
if (entity != null)
{
this.chunkLoader.removeEntity(entity);
entity.remove();
}
}
}

this.isWorldPrepared = false;
this.isActorPrepared = false;
this.generatedEntities = null;

}

@SneakyThrows(StageNotCreatedException.class)
@Override
public void shutdown()
{
this.actorManager.shutdown();
if (this.stageManager.isStageCreated())
this.stageManager.destroyStage(); // StageNotCreatedException はチェック済み。
this.chunkLoader.clear();
this.stageManager.shutdown();
this.chunkLoader.shutdown();


SpigotConfig.disablePlayerDataSaving = false;
Expand Down
Loading

0 comments on commit 43dece8

Please sign in to comment.