restore deleted files (i'm dumb ^_^)
This commit is contained in:
		
							
								
								
									
										353
									
								
								Blocks&ItemsCounter/Source/Blocks&ItemsCounter.as
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										353
									
								
								Blocks&ItemsCounter/Source/Blocks&ItemsCounter.as
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,353 @@ | |||||||
|  | class Objects { //Items or Blocks | ||||||
|  | 	string name; | ||||||
|  | 	int trigger; // CGameItemModel::EnumWaypointType or CGameCtnBlockInfo::EWayPointType | ||||||
|  | 	string type; | ||||||
|  | 	string source; | ||||||
|  | 	int size; | ||||||
|  | 	int count; | ||||||
|  | 	bool icon; | ||||||
|  | 	array<vec3> positions; | ||||||
|  |  | ||||||
|  | 	Objects(string name, int trigger, bool icon, string type, string source, int size, vec3 pos ) { | ||||||
|  | 		this.name = name; | ||||||
|  | 		this.trigger = trigger; | ||||||
|  | 		this.count = 1; | ||||||
|  | 		this.type = type; | ||||||
|  | 		this.icon = icon; | ||||||
|  | 		this.source = source; | ||||||
|  | 		this.size = size; | ||||||
|  | 		this.positions = {pos}; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | enum ESortColumn { | ||||||
|  | 	ItemName, | ||||||
|  | 	Type, | ||||||
|  | 	Source, | ||||||
|  | 	Size, | ||||||
|  | 	Count | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | bool menu_visibility = false; | ||||||
|  | int camerafocusindex = 0; | ||||||
|  | bool include_default_objects = false; | ||||||
|  | bool refreshobject; | ||||||
|  |  | ||||||
|  | bool sort_reverse; | ||||||
|  | bool forcesort; | ||||||
|  | string infotext; | ||||||
|  |  | ||||||
|  | array<Objects@> objects = {}; | ||||||
|  | array<Objects@> sortableobjects = {}; | ||||||
|  | array<string> objectsindex = {}; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ESortColumn sortCol = ESortColumn(-1); | ||||||
|  |  | ||||||
|  | void Main() { | ||||||
|  | 	while (true) { | ||||||
|  | 		if (refreshobject) { | ||||||
|  | 			objects.Resize(0); | ||||||
|  | 			objectsindex.Resize(0); | ||||||
|  | 			sortableobjects.Resize(0); | ||||||
|  | 			RefreshBlocks(); | ||||||
|  | 			RefreshItems(); | ||||||
|  | 			sortableobjects = objects; | ||||||
|  | 			refreshobject = false; | ||||||
|  | 		} | ||||||
|  | 		yield(); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Force to split the refresh functions to bypass the script execution delay on heavy maps | ||||||
|  | void RefreshBlocks() { | ||||||
|  | 	auto map = GetApp().RootMap; | ||||||
|  |  | ||||||
|  | 	if (map !is null) { | ||||||
|  | 		// Blocks | ||||||
|  | 		auto blocks = map.Blocks; | ||||||
|  |  | ||||||
|  | 		// Editor plugin API for GetVec3FromCoord function | ||||||
|  | 		auto pluginmaptype = cast<CGameEditorPluginMapMapType>(cast<CGameCtnEditorFree>(GetApp().Editor).PluginMapType); | ||||||
|  |  | ||||||
|  | 		for(int i = 0; i < blocks.Length; i++) { | ||||||
|  | 			int idifexist = -1; | ||||||
|  | 			string blockname; | ||||||
|  | 			blockname = blocks[i].BlockModel.IdName; | ||||||
|  | 			if (blockname.ToLower().SubStr(blockname.Length - 22, 22) == ".block.gbx_customblock") blockname = blockname.SubStr(0, blockname.Length - 12); | ||||||
|  | 			if (include_default_objects || blockname.ToLower().SubStr(blockname.Length - 10, 10) == ".block.gbx") { | ||||||
|  | 				vec3 pos; | ||||||
|  | 				if (blocks[i].CoordX != 4294967295 && blocks[i].CoordZ != 4294967295) { // Not placed in free mapping | ||||||
|  | 					if (pluginmaptype != null) { // Editor plugin is available | ||||||
|  | 						pos = pluginmaptype.GetVec3FromCoord(blocks[i].Coord); | ||||||
|  | 					} else { | ||||||
|  | 						pos.x = blocks[i].CoordX * 32 + 16; | ||||||
|  | 						pos.y = (blocks[i].CoordY - 8) * 8 + 4; | ||||||
|  | 						pos.z = blocks[i].CoordZ * 32 + 16; | ||||||
|  | 					} | ||||||
|  | 				} else { | ||||||
|  | 					pos = Dev::GetOffsetVec3(blocks[i], 0x6c); | ||||||
|  | 					// center the coordinates in the middle of the block | ||||||
|  | 					pos.x += 16; | ||||||
|  | 					pos.y += 4; | ||||||
|  | 					pos.z += 16; | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 				int index = objectsindex.Find(blockname); | ||||||
|  | 				 | ||||||
|  | 				if (index >= 0) { | ||||||
|  | 					objects[index].count++; | ||||||
|  | 					objects[index].positions.InsertLast(pos); | ||||||
|  | 				} else { | ||||||
|  | 					int trigger = blocks[i].BlockModel.EdWaypointType; | ||||||
|  | 					AddNewObject(blockname, trigger, "Block", pos ); | ||||||
|  | 					objectsindex.InsertLast(blockname); | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			if (i % 100 == 0) yield(); // to avoid timeout | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Force to split the refresh functions to bypass the script execution delay on heavy maps | ||||||
|  | void RefreshItems() { | ||||||
|  | 	auto map = GetApp().RootMap; | ||||||
|  |  | ||||||
|  | 	if (map !is null) { | ||||||
|  | 		// Items | ||||||
|  | 		auto items = map.AnchoredObjects; | ||||||
|  | 		for(int i = 0; i < items.Length; i++) { | ||||||
|  | 			int idifexist = -1; | ||||||
|  | 			string itemname = items[i].ItemModel.IdName; | ||||||
|  | 			if (include_default_objects || itemname.ToLower().SubStr(itemname.Length - 9, 9) == ".item.gbx") { | ||||||
|  | 				int index = objectsindex.Find(itemname); | ||||||
|  | 				if (index >= 0) { | ||||||
|  | 					objects[index].count++; | ||||||
|  | 					objects[index].positions.InsertLast(items[i].AbsolutePositionInMap); | ||||||
|  | 				} else { | ||||||
|  | 					int trigger = items[i].ItemModel.WaypointType; | ||||||
|  | 					AddNewObject(itemname, trigger, "Item", items[i].AbsolutePositionInMap); | ||||||
|  | 					objectsindex.InsertLast(itemname); | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			if (i % 100 == 0) yield(); // to avoid timeout | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void AddNewObject(string objectname, int trigger, string type, vec3 pos) { | ||||||
|  | 	bool icon = false; | ||||||
|  | 	int size; | ||||||
|  | 	string source; | ||||||
|  | 	CSystemFidFile@ file; | ||||||
|  | 	CGameCtnCollector@ collector; | ||||||
|  | 	CSystemFidFile@ tempfile; | ||||||
|  |  | ||||||
|  | 	if (type == "Item" && objectname.SubStr(0,5) == "club:") {//  ItemCollections | ||||||
|  | 		source = "Club"; | ||||||
|  | 		@file = Fids::GetFake('MemoryTemp\\FavoriteClubItems\\' + objectname.SubStr(5,objectname.Length)); | ||||||
|  | 		@collector = cast<CGameCtnCollector>(cast<CGameItemModel>(file.Nod)); | ||||||
|  | 		if (collector is null || (collector.Icon !is null || file.ByteSize == 0)) { | ||||||
|  | 			@tempfile = Fids::GetFake('MemoryTemp\\CurrentMap_EmbeddedFiles\\ContentLoaded\\ClubItems\\' + objectname.SubStr(5,objectname.Length)); | ||||||
|  | 		} | ||||||
|  | 	} else { // Blocks and Items | ||||||
|  | 		source = "Local"; | ||||||
|  | 		@file = Fids::GetUser(type + 's\\' + objectname); | ||||||
|  | 		@collector = cast<CGameCtnCollector>(cast<CGameItemModel>(file.Nod)); | ||||||
|  | 		if (collector is null || (collector.Icon !is null || file.ByteSize == 0)) { | ||||||
|  | 			@tempfile = Fids::GetFake('MemoryTemp\\CurrentMap_EmbeddedFiles\\ContentLoaded\\' + type + 's\\' + objectname); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	if (tempfile !is null) { | ||||||
|  | 		if (collector !is null && collector.Icon !is null && tempfile.ByteSize == 0) { | ||||||
|  | 			icon = true; | ||||||
|  | 			size = file.ByteSize; | ||||||
|  | 		} else  { | ||||||
|  | 			size = tempfile.ByteSize; | ||||||
|  | 		} | ||||||
|  | 		if (file.ByteSize == 0 && tempfile.ByteSize == 0) { | ||||||
|  | 			source = "In-Game"; | ||||||
|  | 		} else if (file.ByteSize == 0 && tempfile.ByteSize > 0) { | ||||||
|  | 			source = "Embedded"; | ||||||
|  | 		} | ||||||
|  | 	} else { | ||||||
|  | 		size = file.ByteSize; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	objects.InsertLast(Objects(objectname, trigger, icon, type, source, size, pos)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool FocusCam(string objectname) { | ||||||
|  | 	auto editor = cast<CGameCtnEditorFree>(GetApp().Editor); | ||||||
|  | 	auto camera = editor.OrbitalCameraControl; | ||||||
|  | 	auto map = GetApp().RootMap; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	if (camera !is null) { | ||||||
|  | 		int index = objectsindex.Find(objectname); | ||||||
|  |  | ||||||
|  | 		camerafocusindex++; | ||||||
|  |  | ||||||
|  | 		if (camerafocusindex > objects[index].positions.get_Length() - 1 ) { | ||||||
|  | 			camerafocusindex = 0; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		camera.m_TargetedPosition = objects[index].positions[camerafocusindex]; | ||||||
|  | 		// Workaround to update camera TargetedPosition | ||||||
|  | 		editor.ButtonZoomInOnClick(); | ||||||
|  | 		editor.ButtonZoomOutOnClick(); | ||||||
|  | 		return true; | ||||||
|  | 	} | ||||||
|  | 	return false; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void GenerateRow(Objects@ object) { | ||||||
|  | 	UI::TableNextRow(); | ||||||
|  | 	UI::TableNextColumn(); | ||||||
|  | 	if (UI::Button(Icons::Search + "###" + object.name)) { | ||||||
|  | 		FocusCam(object.name); | ||||||
|  | 	} | ||||||
|  | 	if (UI::IsItemHovered() && object.type == "Block" && cast<CGameEditorPluginMapMapType>(cast<CGameCtnEditorFree>(GetApp().Editor).PluginMapType) == null) infotext = "Editor plugins are disabled, the coordinates of the blocks are estimated and can be imprecise"; | ||||||
|  | 	UI::SameLine(); | ||||||
|  | 	switch(object.trigger){ | ||||||
|  | 		case CGameCtnBlockInfo::EWayPointType::Start: | ||||||
|  | 			UI::Text("\\$9f9" + object.name); | ||||||
|  | 			if (UI::IsItemHovered()) infotext = "It's a start block/item"; | ||||||
|  | 			break; | ||||||
|  | 		case CGameCtnBlockInfo::EWayPointType::Finish: | ||||||
|  | 			UI::Text("\\$f66" + object.name); | ||||||
|  | 			if (UI::IsItemHovered()) infotext = "It's a finish block/item"; | ||||||
|  | 			break; | ||||||
|  | 		case CGameCtnBlockInfo::EWayPointType::Checkpoint: | ||||||
|  | 			UI::Text("\\$99f" + object.name); | ||||||
|  | 			if (UI::IsItemHovered()) infotext = "It's a checkpoint block/item"; | ||||||
|  | 			break; | ||||||
|  | 		case CGameCtnBlockInfo::EWayPointType::StartFinish: | ||||||
|  | 			UI::Text("\\$ff6" + object.name); | ||||||
|  | 			if (UI::IsItemHovered()) infotext = "It's a multilap block/item"; | ||||||
|  | 			break; | ||||||
|  | 		default: | ||||||
|  | 			UI::Text(object.name); | ||||||
|  | 			break; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	UI::TableNextColumn(); | ||||||
|  | 	UI::Text(object.type); | ||||||
|  | 	UI::TableNextColumn(); | ||||||
|  | 	UI::Text(object.source); | ||||||
|  | 	UI::TableNextColumn(); | ||||||
|  | 	if (object.icon) { | ||||||
|  | 		UI::Text("\\$fc0" + Text::Format("%lld",object.size)); | ||||||
|  | 		if (UI::IsItemHovered()) infotext = "All items with size in orange contains the icon. You must re-open the map to have the real size."; | ||||||
|  | 	} else { | ||||||
|  | 		UI::Text(Text::Format("%lld",object.size)); | ||||||
|  | 	} | ||||||
|  | 	UI::TableNextColumn(); | ||||||
|  | 	UI::Text(Text::Format("%lld",object.count)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Render() { | ||||||
|  | 	if (!menu_visibility) { | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 	infotext = ""; | ||||||
|  | 	auto editor = cast<CGameCtnEditorFree>(GetApp().Editor); | ||||||
|  |  | ||||||
|  | 	UI::SetNextWindowSize(600, 400); | ||||||
|  | 	UI::SetNextWindowPos(200, 200, UI::Cond::Once); | ||||||
|  | 	UI::Begin("\\$cf9" + Icons::Table + "\\$z Blocks & Items Counter###Blocks & Items Counter", menu_visibility); | ||||||
|  | 	if (editor !is null) { | ||||||
|  | 		if (refreshobject) { | ||||||
|  | 			if (Time::get_Now() % 3000 > 2000) { | ||||||
|  | 				UI::Button("Loading..."); | ||||||
|  | 			} else if (Time::get_Now() % 3000 > 1000) { | ||||||
|  | 				UI::Button("Loading.. "); | ||||||
|  | 			} else { | ||||||
|  | 				UI::Button("Loading.  "); | ||||||
|  | 			} | ||||||
|  | 			if (UI::IsItemHovered()) infotext = "Parsing all blocks and items to generate the table. Please wait..."; | ||||||
|  | 		} else { | ||||||
|  | 			if (UI::Button(Icons::SyncAlt + " Refresh")) { | ||||||
|  | 				refreshobject = true; | ||||||
|  | 				forcesort = true; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		UI::SameLine(); | ||||||
|  | 		include_default_objects = UI::Checkbox("Include In-Game Blocks and Items", include_default_objects); | ||||||
|  | 		UI::Separator(); | ||||||
|  | 		vec2 winsize = UI::GetWindowSize(); | ||||||
|  | 		winsize.x = winsize.x-10; | ||||||
|  | 		winsize.y = winsize.y-105; | ||||||
|  | 		if (UI::BeginTable("ItemsTable", 5, UI::TableFlags(UI::TableFlags::Resizable | UI::TableFlags::Sortable | UI::TableFlags::NoSavedSettings | UI::TableFlags::BordersInnerV | UI::TableFlags::SizingStretchProp | UI::TableFlags::ScrollY),winsize )) { | ||||||
|  | 			UI::TableSetupScrollFreeze(0, 1); | ||||||
|  | 			UI::TableSetupColumn("Item Name", UI::TableColumnFlags::None, 55.f, ESortColumn::ItemName);	 | ||||||
|  | 			UI::TableSetupColumn("Type", UI::TableColumnFlags::None, 7.f, ESortColumn::Type); | ||||||
|  | 			UI::TableSetupColumn("Source", UI::TableColumnFlags::None, 13.f, ESortColumn::Source); | ||||||
|  | 			UI::TableSetupColumn("Size", UI::TableColumnFlags::None, 15.f, ESortColumn::Size); | ||||||
|  | 			UI::TableSetupColumn("Count", UI::TableColumnFlags::DefaultSort, 10.f, ESortColumn::Count); | ||||||
|  | 			UI::TableHeadersRow(); | ||||||
|  |  | ||||||
|  | 			UI::TableSortSpecs@ sortSpecs = UI::TableGetSortSpecs(); | ||||||
|  | 			if(sortSpecs !is null && sortSpecs.Specs.Length == 1 && sortableobjects.Length > 1) { | ||||||
|  | 				if(sortSpecs.Dirty || (forcesort && !refreshobject)) { | ||||||
|  | 					if(sortCol != ESortColumn(sortSpecs.Specs[0].ColumnUserID) || (forcesort && !refreshobject)) { | ||||||
|  | 						sortCol = ESortColumn(sortSpecs.Specs[0].ColumnUserID); | ||||||
|  | 						switch(sortCol) { | ||||||
|  | 							case ESortColumn::ItemName: | ||||||
|  | 								sortableobjects.Sort(function(a,b) { return a.name < b.name; }); | ||||||
|  | 								break; | ||||||
|  | 							case ESortColumn::Type: | ||||||
|  | 								sortableobjects.Sort(function(a,b) { return a.type < b.type; }); | ||||||
|  | 								break; | ||||||
|  | 							case ESortColumn::Source: | ||||||
|  | 								sortableobjects.Sort(function(a,b) { return a.source < b.source; }); | ||||||
|  | 								break; | ||||||
|  | 							case ESortColumn::Size: | ||||||
|  | 								sortableobjects.Sort(function(a,b) { return a.size < b.size; }); | ||||||
|  | 								break; | ||||||
|  | 							case ESortColumn::Count: | ||||||
|  | 								sortableobjects.Sort(function(a,b) { return a.count < b.count; }); | ||||||
|  | 								break; | ||||||
|  | 						} | ||||||
|  | 						if (forcesort && sort_reverse) { | ||||||
|  | 							sortableobjects.Reverse(); | ||||||
|  | 						} else { | ||||||
|  | 							sort_reverse = false; | ||||||
|  | 						} | ||||||
|  | 					} else if (sortCol == ESortColumn(sortSpecs.Specs[0].ColumnUserID)) { | ||||||
|  | 						sortableobjects.Reverse(); | ||||||
|  | 						sort_reverse = !sort_reverse; | ||||||
|  | 					} | ||||||
|  |  | ||||||
|  | 					sortSpecs.Dirty = false; | ||||||
|  | 					forcesort = false; | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			if (sortableobjects.Length > 0 ) { | ||||||
|  | 				for(int i = 0; i < sortableobjects.Length; i++) { | ||||||
|  | 					GenerateRow(sortableobjects[i]); | ||||||
|  | 				} | ||||||
|  | 			} else { | ||||||
|  | 				for(int i = 0; i < objects.Length; i++) { | ||||||
|  | 					GenerateRow(objects[i]); | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			UI::EndTable(); | ||||||
|  | 			UI::Separator(); | ||||||
|  | 			UI::Text(Icons::Info + " " + infotext); | ||||||
|  | 		} | ||||||
|  | 	} else { | ||||||
|  | 		UI::Text("Open this plugin in the map editor"); | ||||||
|  | 	} | ||||||
|  | 	UI::End(); | ||||||
|  | 	 | ||||||
|  | } | ||||||
|  | 	 | ||||||
|  | void RenderMenu() { | ||||||
|  | 	if(UI::MenuItem("\\$cf9" + Icons::Table + "\\$z Blocks & Items Counter", "", menu_visibility)) { | ||||||
|  | 		menu_visibility = !menu_visibility; | ||||||
|  | 		refreshobject = true; | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										12
									
								
								Blocks&ItemsCounter/info.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								Blocks&ItemsCounter/info.toml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | |||||||
|  | [meta] | ||||||
|  | name = "Blocks & Items Counter" | ||||||
|  | author = "Beu" | ||||||
|  | category = "Map Editor" | ||||||
|  |  | ||||||
|  | siteid = 97 | ||||||
|  | version = "1.1" | ||||||
|  |  | ||||||
|  | blocks = [ "Plugin_Blocks&ItemsCounter" ] | ||||||
|  |  | ||||||
|  | [script] | ||||||
|  | imports = [ "Icons.as" ] | ||||||
		Reference in New Issue
	
	Block a user