<commit_before>module Firmament

	class Plane

		attr_reader :plane
		attr_reader :dead_tile
		@@planes = ThreadSafe::Cache.new
		@@admins = ThreadSafe::Array.new
		@@servers = ThreadSafe::Cache.new

		def self.admins
			@@admins
		end

		def self.add_admin(admin)
			@@admins << admin
		end

		def self.remove_admin(admin)
			@@admins.delete(admin)
		end

		def self.servers
			@@servers
		end

		def self.server(server)
			return @@servers.fetch(server.to_i, nil)
		end

		def self.add_server(server)
			@@servers[server.plane] = server
		end

		def self.remove_server(plane)
			@@servers.delete(plane)
		end

		attr_reader :pending_deletion, :pending_save

		def initialize(plane)

			@pending_deletion = Queue.new
			@pending_save = Queue.new

			@plane = Entity::Plane.where({plane: plane.to_i}).first
			@@planes[plane.to_i] = self

			@dead_tile = VoidTile.new(@plane.id, VoidTile::DEAD_COORDINATE, VoidTile::DEAD_COORDINATE, VoidTile::DEAD_COORDINATE)

			@scheduler = Rufus::Scheduler.new

			@scheduler.cron '*/15 * * * *', :blocking => true do
				@characters.keys.each do |id|
					char = @characters[id]
					result = Entity::Status.tick char, :ap
					char.broadcast_self result
				end
			end

			@scheduler.cron '* * * * *', :blocking => true do
				@characters.keys.each do |id|
					char = @characters[id]
					result = Entity::Status.tick char, :minute
					char.broadcast_self result
				end
			end

			@scheduler.every '15m', :blocking => true do
				save
			end

			@locations = ThreadSafe::Cache.new do |hashx, x|
				hashx[x.to_i] = ThreadSafe::Cache.new do |hashy, y|
					hashy[y.to_i] = ThreadSafe::Cache.new do |hashz, z|
						#puts "Loading tile ##{x},#{y},#{z}, #{@plane.plane}"

						if Entity::Tile.where({plane: @plane.plane.to_i, x: x.to_i, y: y.to_i, z:z.to_i}).exists? then
							newtile = Entity::Tile.find_by({plane: @plane.plane.to_i, x: x.to_i, y: y.to_i, z:z.to_i})
							newtile.characters = ThreadSafe::Array.new
						else
							newtile = VoidTile.new @plane.plane.to_i, x.to_i, y.to_i, z.to_i
						end

						hashz[z.to_i] = newtile

						Entity::Character.where({plane: @plane.plane.to_i, x: x.to_i, y: y.to_i, z:z.to_i}).each do |char|
							if self.character? char.id.to_i
								newtile.characters << @characters[char.id.to_i]
							else
								char.location = newtile
								@characters[char.id.to_i] = char
								newtile.characters << char
							end
						end

						newtile
					end
				end
			end

			@characters = ThreadSafe::Cache.new do |hash, char_id|
				newchar = Entity::Character.find(char_id)
				hash[newchar.id.to_i] = newchar
				newchar.location = @locations[newchar.x.to_i][newchar.y.to_i][newchar.z.to_i]
				#newchar.location.characters << newchar
				newchar
			end

			@locations[VoidTile::DEAD_COORDINATE][VoidTile::DEAD_COORDINATE][VoidTile::DEAD_COORDINATE] = @dead_tile
		end

		def map(x, y, z)
			@locations[x.to_i][y.to_i][z.to_i]
		end

		def map?(x, y, z)
			!@locations[x.to_i][y.to_i][z.to_i].instance_of?(VoidTile)
		end

		def character(id)
			@characters[id.to_i]
		end

		def character?(id)
			@characters.key? id.to_i
		end

		def unload_character!(id)
			id = id.to_i
			if character? id
				char = character id
				char.location.characters.delete(char)
				@characters.delete(id)
			end
		end

		def self.fetch(name)
			return @@planes.fetch(name.to_i, nil)
		end

		def self.loaded_ids
			@@planes.keys.clone
		end

		def remove_void(x, y ,z)
			return if @locations[x.to_i][y.to_i][z.to_i] === nil
			@locations[x.to_i][y.to_i].delete(z.to_i) if @locations[x.to_i][y.to_i][z.to_i].instance_of?(VoidTile)
		end

		def save
			until @pending_deletion.empty? do
				@pending_deletion.pop.delete
			end
			until @pending_save.empty? do
				@pending_save.pop.save
			end
			@characters.keys.each do |id|
				@characters[id].save
			end
			@locations.keys.each do |x|
				locx = @locations[x]
				locx.keys.each do |y|
					locy = locx[y]
					locy.keys.each do |z|
						locy[z].save
					end
				end
			end
		end

		def sync
			@characters.keys.each do |id|
				@characters[id].statuses.each do |status|
					status.unserialize<commit_msg>Preload map and character data for plane, rather than loading in dynamically<commit_after>module Firmament

	class Plane

		attr_reader :plane
		attr_reader :dead_tile
		@@planes = ThreadSafe::Cache.new
		@@admins = ThreadSafe::Array.new
		@@servers = ThreadSafe::Cache.new

		def self.admins
			@@admins
		end

		def self.add_admin(admin)
			@@admins << admin
		end

		def self.remove_admin(admin)
			@@admins.delete(admin)
		end

		def self.servers
			@@servers
		end

		def self.server(server)
			return @@servers.fetch(server.to_i, nil)
		end

		def self.add_server(server)
			@@servers[server.plane] = server
		end

		def self.remove_server(plane)
			@@servers.delete(plane)
		end

		attr_reader :pending_deletion, :pending_save

		def initialize(plane)

			@pending_deletion = Queue.new
			@pending_save = Queue.new

			@plane = Entity::Plane.where({plane: plane.to_i}).first
			@@planes[plane.to_i] = self

			@dead_tile = VoidTile.new(@plane.id, VoidTile::DEAD_COORDINATE, VoidTile::DEAD_COORDINATE, VoidTile::DEAD_COORDINATE)

			@scheduler = Rufus::Scheduler.new

			@scheduler.cron '*/15 * * * *', :blocking => true do
				@characters.keys.each do |id|
					char = @characters[id]
					result = Entity::Status.tick char, :ap
					char.broadcast_self result
				end
			end

			@scheduler.cron '* * * * *', :blocking => true do
				@characters.keys.each do |id|
					char = @characters[id]
					result = Entity::Status.tick char, :minute
					char.broadcast_self result
				end
			end

			@scheduler.every '15m', :blocking => true do
				save
			end

			@locations = ThreadSafe::Cache.new do |hashx, x|
				hashx[x.to_i] = ThreadSafe::Cache.new do |hashy, y|
					hashy[y.to_i] = ThreadSafe::Cache.new do |hashz, z|
						#puts "Loading tile ##{x},#{y},#{z}, #{@plane.plane}"

						newtile = VoidTile.new(@plane.plane.to_i, x.to_i, y.to_i, z.to_i)

						#if Entity::Tile.where({plane: @plane.plane.to_i, x: x.to_i, y: y.to_i, z:z.to_i}).exists? then
						#	newtile = Entity::Tile.find_by({plane: @plane.plane.to_i, x: x.to_i, y: y.to_i, z:z.to_i})
						#	newtile.characters = ThreadSafe::Array.new
						#else
						#	newtile = VoidTile.new @plane.plane.to_i, x.to_i, y.to_i, z.to_i
						#end

						#hashz[z.to_i] = newtile

						#Entity::Character.where({plane: @plane.plane.to_i, x: x.to_i, y: y.to_i, z:z.to_i}).each do |char|
						#	if self.character? char.id.to_i
						#		newtile.characters << @characters[char.id.to_i]
						#	else
						#		char.location = newtile
						#		@characters[char.id.to_i] = char
						#		newtile.characters << char
						#	end
						#end

						newtile
					end
				end
			end

			@characters = ThreadSafe::Cache.new do |hash, char_id|
				newchar = Entity::Character.find(char_id)
				hash[newchar.id.to_i] = newchar
				newchar.location = @locations[newchar.x.to_i][newchar.y.to_i][newchar.z.to_i]
				#newchar.location.characters << newchar
				newchar
			end

			@locations[VoidTile::DEAD_COORDINATE][VoidTile::DEAD_COORDINATE][VoidTile::DEAD_COORDINATE] = @dead_tile

			# Preload all map tiles and all characters

			puts 'Loading Map...'

			Entity::Tile.where({plane: @plane.plane.to_i}).each do |tile|
				@locations[tile.x][tile.y][tile.z] = tile
			end

			puts 'Loading Characters...'

			Entity::Character.where({plane: @plane.plane.to_i}).each do |newchar|
				newchar.location = @locations[newchar.x][newchar.y][newchar.z]
				@locations[newchar.x][newchar.y][newchar.y].characters << newchar
				@characters[newchar.id] = newchar
			end


		end

		def map(x, y, z)
			@locations[x.to_i][y.to_i][z.to_i]
		end

		def map?(x, y, z)
			!@locations[x.to_i][y.to_i][z.to_i].instance_of?(VoidTile)
		end

		def character(id)
			@characters[id.to_i]
		end

		def character?(id)
			@characters.key? id.to_i
		end

		def unload_character!(id)
			id = id.to_i
			if character? id
				char = character id
				char.location.characters.delete(char)
				@characters.delete(id)
			end
		end

		def self.fetch(name)
			return @@planes.fetch(name.to_i, nil)
		end

		def self.loaded_ids
			@@planes.keys.clone
		end

		def remove_void(x, y ,z)

			x = x.to_i
			y = y.to_i
			z = z.to_i

			if Entity::Tile.where({plane: @plane.plane.to_i, x: x, y: y, z:z}).exists? then
				newtile = Entity::Tile.find_by({plane: @plane.plane.to_i, x: x, y: y, z:z})
				newtile.characters = ThreadSafe::Array.new

				@locations[x][y][z] = newtile

				Entity::Character.where({plane: @plane.plane.to_i, x: x.to_i, y: y.to_i, z:z.to_i}).each do |char|
					if self.character? char.id.to_i
						newtile.characters << @characters[char.id.to_i]
					else
						char.location = newtile
						@characters[char.id.to_i] = char
						newtile.characters << char
					end
				end
			else
				@locations[x][y][z] = VoidTile.new @plane.plane.to_i, x.to_i, y.to_i, z.to_i
			end
		end

		def save
			until @pending_deletion.empty? do
				@pending_deletion.pop.delete
			end
			until @pending_save.empty? do
				@pending_save.pop.save
			end
			@characters.keys.each do |id|
				@characters[id].save
			end
			@locations.keys.each do |x|
				locx = @locations[x]
				locx.keys.each do |y|
					locy = locx[y]
					locy.keys.each do |z|
						locy[z].save
					end
				end
			end
		end

		def sync
			@characters.keys.each do |id|
				@characters[id].statuses.each do |status|
					status.unserialize
{'fraction_non_alphanumeric': 0.14222316145393069, 'fraction_numerical': 0.0008453085376162299, 'mean_word_length': 3.0259464057847723, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1964922', 'n_tokens_mistral': 4589, 'n_tokens_neox': 3690, 'n_words': 705}