content: package org.allaymc.server.world;
  
  import lombok.Builder;
  import lombok.Getter;
  import lombok.Setter;
  import org.allaymc.api.eventbus.event.world.DifficultyChangeEvent;
  import org.allaymc.api.eventbus.event.world.GameRuleChangeEvent;
  import org.allaymc.api.eventbus.event.world.SpawnPointChangeEvent;
  import org.allaymc.api.eventbus.event.world.TimeChangeEvent;
  import org.allaymc.api.pdc.PersistentDataContainer;
  import org.allaymc.api.player.GameMode;
  import org.allaymc.api.registry.Registries;
  import org.allaymc.api.world.World;
  import org.allaymc.api.world.WorldData;
  import org.allaymc.api.world.data.Difficulty;
  import org.allaymc.api.world.gamerule.GameRule;
  import org.allaymc.server.AllayServer;
  import org.allaymc.server.pdc.AllayPersistentDataContainer;
  import org.allaymc.server.world.gamerule.AllayGameRules;
  import org.joml.Vector3i;
  import org.joml.Vector3ic;
  
  @Getter
  @Builder
  public final class AllayWorldData implements WorldData {
  
      private World world;
  
      @Builder.Default
      private Difficulty difficulty = AllayServer.getSettings().genericSettings().defaultDifficulty();
      @Builder.Default
      private GameMode gameMode = AllayServer.getSettings().genericSettings().defaultGameMode();
      @Setter
      @Builder.Default
      private String displayName = DEFAULT_WORLD_DISPLAY_NAME;
      @Builder.Default
      private Vector3ic spawnPoint = new Vector3i(0, 64, 0);
      @Builder.Default
      @Setter
      private long totalTime = 0L;
      @Builder.Default
      private int timeOfDay = TIME_SUNRISE;
      @Builder.Default
      private AllayGameRules gameRules = new AllayGameRules();
      @Getter
      @Builder.Default
      private long worldStartCount = 0;
      @Getter
      @Setter
      @Builder.Default
      private PersistentDataContainer persistentDataContainer = new AllayPersistentDataContainer(Registries.PERSISTENT_DATA_TYPES);
  
      public void setWorld(World world) {
          this.world = world;
          this.gameRules.setWorld(world);
      }
  
      public void setGameMode(GameMode gameMode) {
          this.gameMode = gameMode;
      }
  
      @Override
      public void setDifficulty(Difficulty difficulty) {
          var event = new DifficultyChangeEvent(this.world, this.difficulty, difficulty);
          if (event.call()) {
              this.difficulty = event.getNewDifficulty();
          }
      }
  
      @Override
      public void setTimeOfDay(int timeOfDay) {
          timeOfDay = rollbackTimeOfDay(timeOfDay);
  
          var event = new TimeChangeEvent(this.world, this.timeOfDay, timeOfDay);
          if (!event.call()) {
              return;
          }
  
          this.timeOfDay = event.getNewTime();
          this.world.getPlayers().forEach(player -> player.viewTime(this.world.getWorldData().getTimeOfDay()));
      }
  
      private int rollbackTimeOfDay(int time) {
          if (time < TIME_DAY || time > TIME_FULL) {
              return TIME_DAY;
          }
          return time;
      }
  
      @Override
      public void setGameRuleValue(GameRule gameRule, Object value) {
          var event = new GameRuleChangeEvent(this.world, gameRule, getGameRuleValue(gameRule), value);
          if (event.call()) {
              this.gameRules.set(gameRule, event.getNewValue());
          }
      }
  
      @Override
      public <V> V getGameRuleValue(GameRule gameRule) {
          return gameRules.get(gameRule);
      }
  
      @Override
      public void setSpawnPoint(Vector3ic spawnPoint) {
          var event = new SpawnPointChangeEvent(this.world, this.spawnPoint, spawnPoint);
          if (event.call()) {
              this.spawnPoint = event.getNewPos();
          }
      }
  
      public void increaseWorldStartCount() {
          this.worldStartCount++;
      }
  }
  