Compare commits

..

7 Commits

Author SHA1 Message Date
beu
34a83bd71e fix position when detecting position update from the server 2024-11-02 13:26:36 +01:00
Beu
2d4257b010 Bump to version 1.8
- Allow to enter time in milliseconds like before the 1.6 version
- Add tooltip to display time in milliseconds or in race format
- Add tooltip to explain why validate button is disabled
- Improve valid time detection to allow time in seconds without minutes
2024-02-20 22:19:26 +01:00
Beu
55c5952258 Rework MapValidator + add human readable format 2024-02-18 18:00:52 +01:00
Beu
652bd5fe1a bump version 2023-11-04 11:33:59 +01:00
Beu
14e21b2e4b find a workaround to have size of some blocks and items 2023-11-04 11:25:33 +01:00
Beu
88221039bb update class name 2023-09-27 22:02:49 +02:00
Beu
e986454f80 add permission check 2023-09-27 21:54:58 +02:00
13 changed files with 248 additions and 131 deletions

View File

@ -32,15 +32,18 @@ void RefreshBlocks() {
auto pluginmaptype = cast<CGameEditorPluginMapMapType>(cast<CGameCtnEditorFree>(GetApp().Editor).PluginMapType);
for(uint i = 0; i < blocks.Length; i++) {
int idifexist = -1;
string blockname;
string blockname = blocks[i].BlockModel.IdName;
int fallbacksize = 0;
bool isofficial = true;
blockname = blocks[i].BlockModel.IdName;
if (blockname.ToLower().SubStr(blockname.Length - 22, 22) == ".block.gbx_customblock") {
isofficial = false;
blockname = blockname.SubStr(0, blockname.Length - 12);
auto article = cast<CGameCtnArticle>(blocks[i].BlockInfo.ArticlePtr);
fallbacksize = article.BlockItem_ItemModelArticle.CollectorFid.ByteSize;
}
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
@ -67,7 +70,7 @@ void RefreshBlocks() {
objects[index].positions.InsertLast(pos);
} else {
int trigger = blocks[i].BlockModel.EdWaypointType;
AddNewObject(blockname, trigger, "Block", pos, 0, isofficial);
AddNewObject(blockname, trigger, "Block", pos, fallbacksize, isofficial);
objectsindex.InsertLast(blockname);
}
}
@ -84,7 +87,6 @@ void RefreshItems() {
// Items
auto items = map.AnchoredObjects;
for(uint i = 0; i < items.Length; i++) {
int idifexist = -1;
string itemname = items[i].ItemModel.IdName;
int fallbacksize = 0;
bool isofficial = true;
@ -94,10 +96,9 @@ void RefreshItems() {
auto article = cast<CGameCtnArticle>(items[i].ItemModel.ArticlePtr);
if (article !is null) {
itemname = string(article.PageName) + string(article.Name) + ".Item.Gbx";
} else {
auto fid = cast<CSystemFidFile@>(GetFidFromNod(items[i].ItemModel));
fallbacksize = fid.ByteSize;
}
auto fid = cast<CSystemFidFile@>(GetFidFromNod(items[i].ItemModel));
fallbacksize = fid.ByteSize;
}
if (include_default_objects || itemname.ToLower().SubStr(itemname.Length - 9, 9) == ".item.gbx") {
@ -194,4 +195,4 @@ bool FocusCam(const string &in objectname) {
return true;
}
return false;
}
}

View File

@ -3,5 +3,5 @@ name = "Blocks & Items Counter"
author = "Beu"
category = "Map Editor"
siteid = 97
version = "1.6"
version = "1.7"
blocks = [ "Plugin_Blocks&ItemsCounter" ]

View File

@ -2,7 +2,7 @@
name = "Countdown Mover"
author = "Beu"
category = "Overlay"
version = "1.2"
version = "1.3"
siteid = 431
[script]

View File

@ -25,7 +25,6 @@ class HookCustomizableModuleEvents: MLHook::HookMLEventsByType {
super(C_MLID_UIModuleUpdate);
}
// override this method to avoid reload crash?
void OnEvent(MLHook::PendingEvent@ Event) override {
trace("CustomizableModule updated");
G_Update = true;
@ -64,7 +63,7 @@ void OnSettingsChanged() {
void Main() {
@HookEvents = HookCustomizableModuleEvents();
MLHook::RegisterMLHook(HookEvents, C_MLID_UIModuleUpdate + "_Update", false);
MLHook::RegisterMLHook(HookEvents, C_MLID_UIModuleUpdate + "_Update", true);
MLHook::InjectManialinkToPlayground(C_MLID_UIModuleUpdate, C_ML_UIModuleUpdate, true);
while(true) {

View File

@ -0,0 +1,30 @@
#if MP4
CGameCtnEditorFree@ getEditor() {
return cast<CGameCtnEditorFree>(GetApp().Editor);
}
CGameCtnChallenge@ getMap() {
return cast<CGameCtnChallenge>(GetApp().RootMap);;
}
uint getAuthorTime(CGameCtnChallenge@ _Map) {
return _Map.TMObjective_AuthorTime;
}
void setAuthorTime(CGameCtnChallenge@ _Map, uint _AuthorTime) {
_Map.TMObjective_AuthorTime = _AuthorTime;
// Remove the map UID, the game will generate it again when saving
_Map.IdName = "";
}
void setValidationStatus(CGameCtnEditorFree@ _Editor) {
CGameEditorPluginMapMapType@ pluginmaptype = cast<CGameEditorPluginMapMapType>(_Editor.PluginMapType);
if (pluginmaptype is null) return;
pluginmaptype.ValidationStatus = CGameEditorPluginMapMapType::EValidationStatus::Validated;
}
string GetWarning() {
return "";
}
#endif

View File

@ -0,0 +1,27 @@
#if TMNEXT
CGameCtnEditorFree@ getEditor() {
return cast<CGameCtnEditorFree>(GetApp().Editor);
}
CGameCtnChallenge@ getMap() {
return cast<CGameCtnChallenge>(GetApp().RootMap);;
}
uint getAuthorTime(CGameCtnChallenge@ _Map) {
return _Map.TMObjective_AuthorTime;
}
void setAuthorTime(CGameCtnChallenge@ _Map, uint _AuthorTime) {
_Map.TMObjective_AuthorTime = _AuthorTime;
}
void setValidationStatus(CGameCtnEditorFree@ _Editor) {
CGameEditorPluginMapMapType@ pluginmaptype = cast<CGameEditorPluginMapMapType>(_Editor.PluginMapType);
if (pluginmaptype is null) return;
pluginmaptype.ValidationStatus = CGameEditorPluginMapMapType::EValidationStatus::Validated;
}
string GetWarning() {
return "";
}
#endif

View File

@ -0,0 +1,30 @@
#if TURBO
CGameCtnEditorFree@ getEditor() {
return cast<CGameCtnEditorFree>(GetApp().Editor);
}
CGameCtnChallenge@ getMap() {
return cast<CGameCtnChallenge>(GetApp().Challenge);
}
uint getAuthorTime(CGameCtnChallenge@ _Map) {
return _Map.TMObjective_AuthorTime;
}
void setAuthorTime(CGameCtnChallenge@ _Map, uint _AuthorTime) {
_Map.TMObjective_AuthorTime = _AuthorTime;
// Remove the map UID, the game will generate it again when saving
_Map.IdName = "";
}
void setValidationStatus(CGameCtnEditorFree@ _Editor) {
CGameCtnEditorPluginMapType@ pluginmaptype = cast<CGameCtnEditorPluginMapType>(_Editor.EditorMapType);
if (pluginmaptype is null) return;
pluginmaptype.ValidationStatus = CGameCtnEditorPluginMapType::EValidationStatus::Validated;
}
string GetWarning() {
return "Note: your map must have a start and a finish\n(or a multilap + 1CP) to be validated with the plugin";
}
#endif

View File

@ -0,0 +1,32 @@
#if UNITED
CTrackManiaEditor@ getEditor() {
return cast<CTrackManiaEditor>(cast<CTrackMania>(GetApp()).Editor);
}
CGameCtnChallenge@ getMap() {
return cast<CGameCtnChallenge>(GetApp().Challenge);
}
uint getAuthorTime(CGameCtnChallenge@ _Map) {
return _Map.ChallengeParameters.AuthorTime;
}
void setAuthorTime(CGameCtnChallenge@ _Map, uint _AuthorTime) {
_Map.ChallengeParameters.AuthorTime = _AuthorTime;
_Map.ChallengeParameters.AuthorScore = _AuthorTime;
_Map.ChallengeParameters.GoldTime = Math::Floor((1000 + _AuthorTime + _AuthorTime * 0.06)/1000)*1000;
_Map.ChallengeParameters.SilverTime = Math::Floor((1000 + _AuthorTime + _AuthorTime * 0.2)/1000)*1000;
_Map.ChallengeParameters.BronzeTime = Math::Floor((1000 + _AuthorTime + _AuthorTime * 0.5)/1000)*1000;
// Remove the map UID, the game will generate it again when saving
_Map.IdName = "";
}
void setValidationStatus(CTrackManiaEditor@ _Editor) {
return; // doesn't exists in UNITED
}
string GetWarning() {
return "Note: for an unknown reason, it happens that the times of\nthe medals are not updated, I invite you to check by yourself";
}
#endif

View File

@ -1,128 +1,109 @@
// Based on the Moski plugin which is also based on the Miss plugin :)
bool menu_visibility = false;
int author_time;
const string C_InvalidValueError = "Invalid value. You can set a human readable value like \\$<\\$aaa1:23.456\\$>\nor a value in milliseconds like \\$<\\$aaa83456\\$>";
void Main() {}
bool G_MenuVisibility = false;
string G_AuthorTimeText = "0:00:00.000";
void validate(int author_time) {
// Get editor var
#if UNITED
CTrackManiaEditor@ editor = cast<CTrackManiaEditor>(cast<CTrackMania>(GetApp()).Editor);
#else
CGameCtnEditorFree@ editor = cast<CGameCtnEditorFree>(GetApp().Editor);
#endif
// Get map & pluginmaptype if possible
#if TURBO
CGameCtnChallenge@ map = cast<CGameCtnChallenge>(GetApp().Challenge);
CGameCtnEditorPluginMapType@ pluginmaptype = cast<CGameCtnEditorPluginMapType>(editor.EditorMapType);
#elif UNITED
CGameCtnChallenge@ map = cast<CGameCtnChallenge>(GetApp().Challenge);
auto pluginmaptype == null;
#else
CGameCtnChallenge@ map = cast<CGameCtnChallenge>(GetApp().RootMap);
CGameEditorPluginMapMapType@ pluginmaptype = cast<CGameEditorPluginMapMapType>(editor.PluginMapType);
#endif
if (editor is null) {
return;
}
if (pluginmaptype !is null) {
#if TURBO
pluginmaptype.ValidationStatus = CGameCtnEditorPluginMapType::EValidationStatus::Validated;
#else
pluginmaptype.ValidationStatus = CGameEditorPluginMapMapType::EValidationStatus::Validated;
#endif
}
if (map !is null) {
#if UNITED
map.ChallengeParameters.AuthorTime = author_time;
map.ChallengeParameters.AuthorScore = author_time;
map.ChallengeParameters.GoldTime = Math::Floor((1000 + author_time + author_time * 0.06)/1000)*1000;
map.ChallengeParameters.SilverTime = Math::Floor((1000 + author_time + author_time * 0.2)/1000)*1000;
map.ChallengeParameters.BronzeTime = Math::Floor((1000 + author_time + author_time * 0.5)/1000)*1000;
#else
map.TMObjective_AuthorTime = author_time;
#endif
#if !TMNEXT
map.IdName = ""; // Remove the map UID, the game will generate it again when saving
#endif
}
}
void Main() {}
void Render() {
if (!menu_visibility) {
auto editor = getEditor();
if (editor is null) {
G_MenuVisibility = false;
return;
}
auto map = getMap();
if (map is null) {
G_MenuVisibility = false;
return;
}
#if UNITED
CTrackManiaEditor@ editor = cast<CTrackManiaEditor>(cast<CTrackMania>(GetApp()).Editor);
#else
CGameCtnEditorFree@ editor = cast<CGameCtnEditorFree>(GetApp().Editor);
#endif
#if TMNEXT || MP4
CGameCtnChallenge@ map = cast<CGameCtnChallenge>(GetApp().RootMap);
#else
CGameCtnChallenge@ map = cast<CGameCtnChallenge>(GetApp().Challenge);
#endif
if (map is null || editor is null) {
menu_visibility = false;
if (!G_MenuVisibility) {
// Store the last Author Time when hidden
uint CurrentAuthorTime = getAuthorTime(map);
if (CurrentAuthorTime < 4294967295) {
G_AuthorTimeText = Time::Format(CurrentAuthorTime);
}
return;
}
if (UI::Begin("\\$cf9" + Icons::Flag + "\\$z Map Validator###MapValidator", menu_visibility, UI::WindowFlags::NoResize | UI::WindowFlags::AlwaysAutoResize | UI::WindowFlags::NoCollapse)){
author_time = UI::InputInt("Author time in ms", author_time ,1);
if (author_time < 0) author_time = 0;
if (UI::Button("Validate")) {
validate(author_time);
menu_visibility = false;
}
// Convert time in ms to humain readable time
string display_time = Text::Format('%02d',(author_time / 1000 / 60) % 60) + ":" + Text::Format('%02d',(author_time / 1000) % 60) + "." + Text::Format('%03d',author_time % 1000);
if (Math::Floor(author_time / 1000 / 60 / 60) > 0) {
display_time = Text::Format('%d',author_time / 1000 / 60 / 60) + ":" + display_time;
}
UI::SetNextItemWidth(200.0);
if (UI::Begin("\\$cf9" + Icons::Flag + "\\$z Map Validator###MapValidator", G_MenuVisibility, UI::WindowFlags::NoResize | UI::WindowFlags::AlwaysAutoResize | UI::WindowFlags::NoCollapse)){
UI::SetNextItemWidth(100.0);
G_AuthorTimeText = UI::InputText("###AuthorTimeText", G_AuthorTimeText);
UI::SameLine();
UI::Text("with " + display_time + " of author time");
#if TURBO
UI::Text("Note: your map must have a start and a finish\n(or a multilap + 1CP) to be validated with the plugin");
#elif UNITED
UI::Text("Note: for an unknown reason, it happens that the times of\nthe medals are not updated, I invite you to check by yourself");
#endif
const bool IsMilliseconds = IsMillisecondsFormat(G_AuthorTimeText);
const bool IsButtonDisabled = (!IsMilliseconds && !IsValidAuthorTime(G_AuthorTimeText));
UI::End();
}
// Creating group to be able to display the tooltip even when the button is disabled
UI::BeginGroup();
UI::BeginDisabled(IsButtonDisabled);
if (UI::Button("Validate")) {
int AuthorTime = 0;
if (IsMilliseconds) AuthorTime = Text::ParseUInt(G_AuthorTimeText);
else AuthorTime = Time::ParseRelativeTime(G_AuthorTimeText);
setAuthorTime(map, AuthorTime);
setValidationStatus(editor);
G_MenuVisibility = false;
}
UI::EndDisabled();
UI::EndGroup();
// Time tooltip
if (UI::IsItemHovered()) {
UI::BeginTooltip();
if (IsButtonDisabled) {
UI::Text(C_InvalidValueError);
} else if (IsMilliseconds) {
UI::Text(Time::Format(Text::ParseUInt(G_AuthorTimeText)));
} else {
UI::Text("" + Time::ParseRelativeTime(G_AuthorTimeText) + " ms");
}
UI::EndTooltip();
}
// Warning tooltip depending the game
const string warning = GetWarning();
if (warning != "") {
UI::SameLine();
UI::Text("\\$fa2" + Icons::Info);
if (UI::IsItemHovered()) {
UI::BeginTooltip();
UI::Text(warning);
UI::EndTooltip();
}
}
}
UI::End();
}
void RenderMenu() {
#if UNITED
CTrackManiaEditor@ editor = cast<CTrackManiaEditor>(cast<CTrackMania>(GetApp()).Editor);
#else
CGameCtnEditorFree@ editor = cast<CGameCtnEditorFree>(GetApp().Editor);
#endif
auto editor = getEditor();
if (editor is null) return;
#if TMNEXT || MP4
CGameCtnChallenge@ map = cast<CGameCtnChallenge>(GetApp().RootMap);
#else
CGameCtnChallenge@ map = cast<CGameCtnChallenge>(GetApp().Challenge);
#endif
auto map = getMap();
if (map is null) return;
if (map is null || editor is null) {
return;
}
if(UI::MenuItem("\\$cf9" + Icons::Flag + "\\$z Map Validator", "", menu_visibility)) {
menu_visibility = !menu_visibility;
if(UI::MenuItem("\\$cf9" + Icons::Flag + "\\$z Map Validator", "", G_MenuVisibility)) {
G_MenuVisibility = !G_MenuVisibility;
}
}
bool IsMillisecondsFormat(string _AuthorTimeText) {
return Regex::IsMatch(_AuthorTimeText, '\\d+');
}
bool IsValidAuthorTime(string _AuthorTimeText) {
if (!Regex::IsMatch(_AuthorTimeText, '[\\d\\.:]+')) {
return false;
}
if (!Regex::IsMatch(_AuthorTimeText, '^(((((\\d+:)?[0-5])?\\d:)?[0-5])?\\d)\\.\\d{3}$')) {
return false;
}
return true;
}

View File

@ -1,9 +1,8 @@
[meta]
name = "Map Validator"
author = "Beu"
category = "Map Editor"
siteid = 91
version = "1.6"
blocks = [ "Plugin_MapValidator" ]
[meta]
name = "Map Validator"
author = "Beu"
category = "Map Editor"
siteid = 91
version = "1.8"
blocks = [ "Plugin_MapValidator" ]

View File

@ -3,6 +3,7 @@ uint S_NbOfLinksInCache = 5;
const string C_LinksCache = "LinksCache.txt";
bool G_PermissionIssueNotified = false;
string G_QuickURL = "";
bool G_PressEnter = false;
bool G_WasEditing = false;
@ -10,6 +11,8 @@ bool G_WasEditing = false;
array<string> G_LinksCache;
void Main() {
if (!hasPermissions()) return;
trace("Loading links cache");
string filepath = IO::FromStorageFolder(C_LinksCache);
IO::File file(filepath);
@ -21,6 +24,8 @@ void Main() {
}
void RenderMenuMain() {
if (!hasPermissions()) return;
if (!G_PressEnter && UI::BeginMenu("\\$cf9" + Icons::ExternalLink + "\\$z Quick Link Opener##QuickLinkOpenerMenu")) {
G_QuickURL = UI::InputText("###quickURL", G_QuickURL, G_PressEnter, UI::InputTextFlags::EnterReturnsTrue + UI::InputTextFlags::CallbackAlways, UI::InputTextCallback(ITCB));
@ -48,6 +53,7 @@ void ITCB(UI::InputTextCallbackData@ d) {
}
void LoadLink(string _Url, bool _NewUrl) {
if (!hasPermissions()) return;
if (_Url == "") return;
string parsedURL = "";
@ -78,3 +84,15 @@ void LoadLink(string _Url, bool _NewUrl) {
CTrackMania@ app = cast<CTrackMania>(GetApp());
app.ManiaPlanetScriptAPI.OpenLink(parsedURL, CGameManiaPlanetScriptAPI::ELinkType::ManialinkBrowser);
}
bool hasPermissions() {
if (Permissions::PlayPublicClubRoom()) return true;
if (!G_PermissionIssueNotified) {
G_PermissionIssueNotified = true;
string msg = "Missing permissions: you need to be able to play on public room to use this plugin.";
warn(msg);
UI::ShowNotification(Meta::ExecutingPlugin().Name, msg, vec4(.9, .5, .3, .2), 15000);
}
return false;
}

View File

@ -1,6 +1,6 @@
[meta]
name = "TMWT Interfaces Remover"
category = "TMWT"
version = "1.3"
version = "1.4"
siteid = 318

View File

@ -1,4 +1,4 @@
const string C_Class_UIModules = 'component-modelibs-uimodules-module';
const string C_Class_UIModules = 'component-cmgame-uimodules-module';
const string C_Id_TMWT_LiveRanking = 'TMWTCommon_LiveRanking';
const string C_Id_TMWT_Header = 'TMWTCommon_Header';
const string C_Id_TMWC2023_LiveRanking = 'TMWC2023_LiveRanking';