Compare commits

...

3 commits

Author SHA1 Message Date
f8eb9909f2 Re-add import 2024-09-25 12:31:00 -05:00
6902a8f744 Add missing incl file 2024-09-25 12:30:49 -05:00
9352c5b7d0 Some refactoring to help fix bug 2024-09-25 11:50:18 -05:00
7 changed files with 185 additions and 16 deletions

Binary file not shown.

View file

@ -0,0 +1,155 @@
#if defined _editor_included_
#endinput
#endif
#define _editor_included_
public SharedPlugin __pl_editor_ = {
name = "editor",
file = "hats.smx",
#if defined REQUIRE_PLUGIN
required = 1,
#else
required = 0,
#endif
};
#if !defined REQUIRE_PLUGIN
public void __pl_editor__SetNTVOptional()
{
MarkNativeAsOptional("SpawnSchematic");
MarkNativeAsOptional("StartEdit");
MarkNativeAsOptional("StartSpawner");
MarkNativeAsOptional("CancelEdit");
MarkNativeAsOptional("IsEditorActive");
MarkNativeAsOptional("StartSelector");
MarkNativeAsOptional("CancelSelector");
MarkNativeAsOptional("IsSelectorActive");
MarkNativeAsOptional("Selector.Count.get");
MarkNativeAsOptional("Selector.Active.get");
MarkNativeAsOptional("Selector.Start");
MarkNativeAsOptional("Selector.SetOnEnd");
MarkNativeAsOptional("Selector.SetOnPreSelect");
MarkNativeAsOptional("Selector.SetOnPostSelect");
MarkNativeAsOptional("Selector.SetOnUnselect");
MarkNativeAsOptional("Selector.AddEntity");
MarkNativeAsOptional("Selector.RemoveEntity");
MarkNativeAsOptional("Selector.Cancel");
MarkNativeAsOptional("Selector.End");
}
#endif
native bool SpawnSchematic(const char name[32], const float pos[3], const float angles[3] = NULL_VECTOR);
/** Called when edit is done or cancelled
* @param client - client doing the edit
* @param entity - The entity edited
* @param result - Result of the edit, or cancelled
* @return boolean - only for StartSpawner, true to continue, false to end spawning
*/
typeset EditorDoneCallback {
function void (int client, int entity, CompleteType result);
function bool (int client, int entity, CompleteType result);
}
/** Called when an item is to be selected.
* @return boolean - TRUE to allow item to be selected, FALSE to reject
*/
typedef SelectPreAddCallback = function bool (int client, int entity);
/** Called when an item has been selected */
typedef SelectPostAddCallback = function void (int client, int entity);
/** Called when an item is to be unselected. */
typedef SelectRemoveCallback = function void (int client, int entity);
/** Called when a user is done selecting items
* @param client - client doing the selection
* @param entities - if null, selection was cancelled. if not null, contains list of entity references, must be deleted.
*/
typedef SelectDoneCallback = function void (int client, ArrayList entities);
/** Starts editing an entity
* @param client - The client that is editing
* @param entity - The entity to edit
* @param doneCallback - Called when edit is done
*/
native void StartEdit(int client, int entity, EditorDoneCallback doneCallback);
/** Let client pick prop(s) to spawn
* @param client - The client that is editing
* @param entity - The entity to edit
* @param doneCallback - Called when edit is done
*/
native void StartSpawner(int client, EditorDoneCallback doneCallback);
native void CancelEdit(int client);
// Includes non-plugin started edits
native bool IsEditorActive(int client);
/** Starts a selection, where the client can click on entities to select or deselect them.
* @param client - the client that can select
* @param callback - called when user is done seleting or cancelled
* @param highlightColor - the color to highlight selected items, default solid green
* @param maxEntities - the max number of selections, 0 for infinite
*/
native void StartSelector(int client, SelectDoneCallback callback, int highlightColor[3] = { 0, 255, 0 }, int maxEntities = 0);
methodmap EntitySelector {
public EntitySelector(int client) {
return view_as<EntitySelector>(client);
}
public static EntitySelector FromClient(int client) {
return view_as<EntitySelector>(client);
}
/** Starts a new selector for client
* @param highlightColor - the color to highlight selected items, default solid green
* @param flags - not used.
* @param maxEntities - the max number of selections, 0 for infinite
*/
public native EntitySelector Start(int highlightColor[3], int flags = 0, int maxEntities = 0);
property int Count {
/** Returns the number of entities in selector. Returns -1 if not active */
public native get();
}
property bool Active {
public native get();
}
/** Sets the callback for when the selector is ended (or cancelled) */
public native void SetOnEnd(SelectDoneCallback callback);
/** Sets the callback for when an item is to be added to the selector. */
public native void SetOnPreSelect(SelectPreAddCallback callback);
/** Sets the callback for when an item has been added to the selector. */
public native void SetOnPostSelect(SelectPostAddCallback callback);
/** Sets the callback for when an item is removed from selector. */
public native void SetOnUnselect(SelectRemoveCallback callback);
/** Adds an entity to selection. Does not call SelectAddCallback */
public native void AddEntity(int entity);
/** Removes an entity from selection. Does not call SelectAddCallback */
public native void RemoveEntity(int entity);
public native void Cancel();
public native void End();
}
native void CancelSelector(int client);
native bool IsSelectorActive(int client);
enum CompleteType {
Complete_WallSuccess,
Complete_WallError,
Complete_PropSpawned,
Complete_PropError,
Complete_EditSuccess
}

View file

@ -138,6 +138,7 @@ public any Native_SpawnSchematic(Handle plugin, int numParams) {
return true;
}
enum struct PropSelectorIterator {
ArrayList _list;
int _index;
@ -335,10 +336,17 @@ enum struct PropSelector {
return -1;
}
}
enum itemMenuFlag {
// Do not change flags
IMF_NoChange = -1,
IMF_None = 0,
// Delete underlying item buffer when done using it (for temp buffers, such as search results)
IMF_DeleteAfterUse = 1
}
enum struct PlayerPropData {
ArrayList categoryStack;
ArrayList itemBuffer;
bool clearListBuffer;
int bufferFlags; // itemMenuFlag, IMF_*
int lastCategoryIndex;
int lastItemIndex;
// When did the user last interact with prop spawner? (Shows hints after long inactivity)
@ -359,7 +367,7 @@ enum struct PlayerPropData {
void Reset() {
if(this.Selector.IsActive()) this.Selector.Cancel();
this.chatPrompt = Prompt_None;
this.clearListBuffer = false;
this.bufferFlags = IMF_None;
this.lastCategoryIndex = 0;
this.lastItemIndex = 0;
this.lastActiveTime = 0;
@ -389,18 +397,20 @@ enum struct PlayerPropData {
ShowCategoryList(client, ROOT_CATEGORY);
}
// Sets the list buffer
void SetItemBuffer(ArrayList list, bool cleanupAfterUse = false) {
// Sets the list buffer, with optional flags. If no flags set, uses current flags
void SetItemBuffer(ArrayList list, int flags = IMF_NoChange) {
// Cleanup previous buffer if exist
this.itemBuffer = list;
this.clearListBuffer = cleanupAfterUse;
if(flags != view_as<int>(IMF_NoChange)) {
this.bufferFlags = flags;
}
}
void ClearItemBuffer() {
if(this.itemBuffer != null && this.clearListBuffer) {
if(this.itemBuffer != null && this.bufferFlags & view_as<int>(IMF_DeleteAfterUse)) {
PrintToServer("ClearItemBuffer(): arraylist deleted.");
delete this.itemBuffer;
}
this.clearListBuffer = false;
this.bufferFlags = IMF_None;
}
void PushCategory(CategoryData category) {
@ -443,7 +453,6 @@ enum struct PlayerPropData {
if(this.categoryStack != null) {
delete this.categoryStack;
}
this.clearListBuffer = false;
}
}
PlayerPropData g_PropData[MAXPLAYERS+1];

View file

@ -69,7 +69,7 @@ Action Command_Props(int client, int args) {
}
}
PrintToChat(client, "\x04[Editor]\x01 Check console");
} else if(StrEqual(arg, "search")) {
} else if(StrEqual(arg, "?q") || StrEqual(arg, "search")) {
if(args == 1) {
PrintToChat(client, "\x04[Editor]\x01 Enter your search query:");
g_PropData[client].chatPrompt = Prompt_Search;

View file

@ -344,12 +344,12 @@ int ManagerSelectorActionHandler(Menu menu, MenuAction action, int client, int p
Spawn_ShowManagerMainMenu(client);
} else if(StrEqual(info, "save_scene")) {
ArrayList items = g_PropData[client].Selector.End();
g_PropData[client].SetItemBuffer(items, true);
g_PropData[client].SetItemBuffer(items, IMF_DeleteAfterUse);
g_PropData[client].chatPrompt = Prompt_SaveScene;
SendEditorMessage(client, "Enter name for scene:");
} else if(StrEqual(info, "save_collection")) {
ArrayList items = g_PropData[client].Selector.End();
g_PropData[client].SetItemBuffer(items, true);
g_PropData[client].SetItemBuffer(items, IMF_DeleteAfterUse);
g_PropData[client].chatPrompt = Prompt_SaveCollection;
SendEditorMessage(client, "Enter name for collection:");
} else {

View file

@ -109,7 +109,9 @@ void ShowCategoryList(int client, CategoryData category) {
int index = g_PropData[client].lastCategoryIndex / 7 * 7;
menu.DisplayAt(client, index, MENU_TIME_FOREVER);
}
void _showItemMenu(int client, ArrayList items, const char[] title = "", bool clearArray = false, const char[] classnameOverride = "") {
void _showItemMenu(int client, ArrayList items, const char[] title = "", int flags = IMF_None, const char[] classnameOverride = "") {
if(items == null) {
// Use previous list buffer
items = g_PropData[client].itemBuffer;
@ -120,7 +122,7 @@ void _showItemMenu(int client, ArrayList items, const char[] title = "", bool cl
}
} else {
// Populate the buffer with this list
g_PropData[client].SetItemBuffer(items, clearArray);
g_PropData[client].SetItemBuffer(items, flags);
// Reset the index, so we start on the first item
g_PropData[client].lastItemIndex = 0;
strcopy(g_PropData[client].classnameOverride, 32, classnameOverride);
@ -168,7 +170,7 @@ void ShowCategoryItemMenu(int client, CategoryData category) {
* @param classnameOverride Override the classname to spawn as
*/
void ShowItemMenu(int client, ArrayList items = null, const char[] title = "", const char[] classnameOverride = "") {
_showItemMenu(client, items, title, false, classnameOverride);
_showItemMenu(client, items, title, IMF_NoChange, classnameOverride);
}
/**
* Show a list of items, deleting the arraylist on completion
@ -181,7 +183,7 @@ void ShowTempItemMenu(int client, ArrayList items, const char[] title = "", cons
if(items == null) {
LogError("ShowTempItemMenu: Given null item list");
}
_showItemMenu(client, items, title, true, classnameOverride);
_showItemMenu(client, items, title, IMF_DeleteAfterUse, classnameOverride);
}
void Spawn_ShowFavorites(int client) {

View file

@ -389,7 +389,7 @@ public Action OnClientSayCommand(int client, const char[] command, const char[]
void DoSearch(int client, const char[] query) {
ArrayList results = SearchItems(query);
if(results.Length == 0) {
CPrintToChat(client, "\x04[Editor]\x01 No results found. :(");
CPrintToChat(client, "\x04[Editor]\x01 No results found for \x05%s\x01 :(", query);
} else {
char title[64];
Format(title, sizeof(title), "Results for \"%s\"", query);
@ -464,6 +464,9 @@ bool _searchItems(ArrayList results, ArrayList items, const char[] query) {
for(int i = 0; i < items.Length; i++) {
items.GetArray(i, item);
int searchIndex = StrContains(item.name, query, false);
// Search model if name doesn't match
// item.model: models/...., we cut out models/ part
if(searchIndex == -1) searchIndex = StrContains(item.model[7], query, false);
if(searchIndex > -1) {
search.FromItemData(item);
search.index = searchIndex;