Update things

This commit is contained in:
Jackzie 2024-03-06 17:59:55 -06:00
parent 9590ceb207
commit d4f9241b3c
25 changed files with 650 additions and 345 deletions

View file

@ -155,7 +155,7 @@ enum struct EditorData {
bool CheckEntity() {
if(this.entity != INVALID_ENT_REFERENCE) {
if(!IsValidEntity(this.entity)) {
if(this.entity == -1 && !IsValidEntity(this.entity)) {
PrintToChat(this.client, "\x04[Editor]\x01 Entity has vanished, editing cancelled.");
this.Reset();
return false;
@ -301,7 +301,7 @@ enum struct EditorData {
char component[16];
for(int i = 0; i < 4; i++) {
if(this.colorIndex == i)
Format(component, sizeof(component), "%s \x05 %c \x01", component, COLOR_INDEX[i]);
Format(component, sizeof(component), "%s \x05%c\x01", component, COLOR_INDEX[i]);
else
Format(component, sizeof(component), "%s %c", component, COLOR_INDEX[i]);
}

View file

@ -1,5 +1,9 @@
char g_pendingSaveName[64];
int g_pendingSaveClient;
ArrayList g_previewItems;
CategoryData ROOT_CATEGORY;
ArrayList g_spawnedItems; // ArrayList(block=2)<entRef, [creator]>
ArrayList g_savedItems; // ArrayList<entRef>
StringMap g_recentItems; // Key: model[128], value: RecentEntry
/* Wish to preface this file:
* It's kinda messy. The main structs are:
@ -12,7 +16,123 @@ The rest are kinda necessary, for sorting reasons (SearchData, RecentEntry).
enum ChatPrompt {
Prompt_None,
Prompt_Search,
Prompt_Save
Prompt_SaveScene,
Prompt_SaveSchematic
}
enum SaveType {
Save_None,
Save_Scene,
Save_Schematic
}
enum struct Schematic {
char name[64];
char creatorSteamid[32];
char creatorName[32];
ArrayList entities;
void Reset() {
this.name[0] = '\0';
this.creatorSteamid[0] = '\0';
this.creatorName[0] = '\0';
if(this.entities != null) delete this.entities;
}
void AddEntity(int entity, int client) {
SaveData save;
save.FromEntity(entity);
this.entities.PushArray(save);
}
void New(int client, const char[] name) {
if(client > 0) {
GetClientName(client, this.creatorName, sizeof(this.creatorName));
GetClientAuthId(client, AuthId_Steam2, this.creatorSteamid, sizeof(this.creatorSteamid));
}
strcopy(this.name, sizeof(this.name), name);
this.entities = new ArrayList(sizeof(SaveData));
}
bool Save() {
char path[PLATFORM_MAX_PATH];
BuildPath(Path_SM, path, sizeof(path), "data/prop_spawner/schematics/%s.schem", this.name);
CreateDirectory("data/prop_spawner/schematics", 0775);
KeyValues kv = new KeyValues(this.name);
kv.SetString("creator_steamid", this.creatorSteamid);
kv.SetString("creator_name", this.creatorName);
kv.JumpToKey("entities");
this.entities = new ArrayList(sizeof(SaveData));
SaveData ent;
while(kv.GotoNextKey()) {
kv.GetVector("offset", ent.origin);
kv.GetVector("angles", ent.angles);
kv.GetColor4("color", ent.color);
kv.GetString("model", ent.model, sizeof(ent.model));
this.entities.PushArray(ent);
}
kv.ExportToFile(path);
delete kv;
return true;
}
bool Import(const char[] name) {
char path[PLATFORM_MAX_PATH];
BuildPath(Path_SM, path, sizeof(path), "data/prop_spawner/schematics/%s.schem", name);
KeyValues kv = new KeyValues("root");
if(kv.ImportFromFile(path)) {
delete kv;
return false;
}
strcopy(this.name, sizeof(this.name), name);
kv.GetString("creator_steamid", this.creatorSteamid, sizeof(this.creatorSteamid));
kv.GetString("creator_name", this.creatorName, sizeof(this.creatorName));
kv.JumpToKey("entities");
this.entities = new ArrayList(sizeof(SaveData));
SaveData ent;
while(kv.GotoNextKey()) {
kv.GetVector("offset", ent.origin);
kv.GetVector("angles", ent.angles);
kv.GetColor4("color", ent.color);
kv.GetString("model", ent.model, sizeof(ent.model));
this.entities.PushArray(ent);
}
delete kv;
return true;
}
/// Spawns all schematics entities, returns list of entities, first being parent.
ArrayList SpawnEntities(const float origin[3], bool asPreview = true) {
if(this.entities == null) return null;
SaveData ent;
int parent = -1;
ArrayList spawnedEntities = new ArrayList();
for(int i = 0; i < this.entities.Length; i++) {
this.entities.GetArray(i, ent, sizeof(ent));
int entity = ent.ToEntity(origin, asPreview);
spawnedEntities.Push(EntIndexToEntRef(entity));
if(i == 0) {
SetParent(entity, parent)
} else {
parent = entity;
}
}
return spawnedEntities;
}
}
public any Native_SpawnSchematic(Handle plugin, int numParams) {
char name[32];
float pos[3];
float ang[3];
GetNativeString(0, name, sizeof(name));
GetNativeArray(1, pos, 3);
GetNativeArray(1, ang, 3);
Schematic schem;
if(!schem.Import(name)) {
return false;
}
ArrayList list = schem.SpawnEntities(pos, false);
delete list;
return true;
}
enum struct PlayerPropData {
ArrayList categoryStack;
@ -25,6 +145,9 @@ enum struct PlayerPropData {
char classnameOverride[64];
ChatPrompt chatPrompt;
ArrayList markedProps;
SaveType pendingSaveType;
Schematic schematic;
// Called on PlayerDisconnect
void Reset() {
@ -36,6 +159,15 @@ enum struct PlayerPropData {
this.lastActiveTime = 0;
this.classnameOverride[0] = '\0';
this.CleanupBuffers();
this.pendingSaveType = Save_None;
this.schematic.Reset();
}
void StartSchematic(int client, const char[] name) {
this.schematic.New(client, name);
this.pendingSaveType = Save_Schematic;
PrintToChat(client, "\x04[Editor]\x01 Started new schematic: \x05%s", name);
ShowCategoryList(client, ROOT_CATEGORY);
}
// Sets the list buffer
@ -97,6 +229,7 @@ enum struct PlayerPropData {
}
PlayerPropData g_PropData[MAXPLAYERS+1];
enum struct CategoryData {
// The display name of category
char name[64];
@ -124,6 +257,8 @@ enum struct SearchData {
strcopy(this.name, sizeof(this.name), item.name);
}
}
enum struct SaveData {
char model[128];
buildType type;
@ -148,6 +283,43 @@ enum struct SaveData {
GetEntityRenderColor(entity, this.color[0],this.color[1],this.color[2],this.color[3]);
}
int ToEntity(const float offset[3], bool asPreview = true) {
int entity = -1;
if(this.type == Build_Physics)
entity = CreateEntityByName("prop_physics");
else
entity = CreateEntityByName("prop_dynamic_override");
if(entity == -1) {
return -1;
}
PrecacheModel(this.model);
DispatchKeyValue(entity, "model", this.model);
DispatchKeyValue(entity, "targetname", "saved_prop");
if(asPreview) {
DispatchKeyValue(entity, "rendermode", "1");
DispatchKeyValue(entity, "solid", "0");
} else {
DispatchKeyValue(entity, "solid", this.type == Build_NonSolid ? "0" : "6");
}
float pos[3];
for(int i = 0; i < 3; i++)
pos[i] = this.origin[i] + offset[i];
TeleportEntity(entity, pos, this.angles, NULL_VECTOR);
if(!DispatchSpawn(entity)) {
return -1;
}
int alpha = asPreview ? 200 : this.color[3];
SetEntityRenderColor(entity, this.color[0], this.color[1], this.color[2], alpha);
if(asPreview)
g_previewItems.Push(EntIndexToEntRef(entity));
else
AddSpawnedItem(entity);
return entity;
}
void Serialize(char[] output, int maxlen) {
Format(
output, maxlen, "%s,%d,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%d,%d,%d,%d",
@ -181,10 +353,6 @@ enum struct RecentEntry {
char name[64];
int count;
}
CategoryData ROOT_CATEGORY;
ArrayList g_spawnedItems; // ArrayList(block=2)<entRef, [creator]>
ArrayList g_savedItems; // ArrayList<entRef>
StringMap g_recentItems; // Key: model[128], value: RecentEntry
#include <hats/props/db.sp>
#include <hats/props/methods.sp>

View file

@ -12,6 +12,27 @@ Action Command_Props(int client, int args) {
PrintToConsole(client, "favorite - favorites active editor entity");
PrintToConsole(client, "controls - list all the controls");
PrintToConsole(client, "reload - reload prop list");
PrintToConsole(client, "schem[atic] <new/save/edit/delete/load> <name>");
} else if(StrEqual(arg, "schem") || StrEqual(arg, "schematic")) {
char arg2[16];
GetCmdArg(2, arg2, sizeof(arg2));
if(StrEqual(arg2, "new")) {
char name[32];
GetCmdArg(3, name, sizeof(name));
if(name[0] == '\0') {
PrintToChat(client, "\x04[Editor]\x01 Please enter a name");
} else {
g_PropData[client].StartSchematic(client, name);
}
} else if(StrEqual(arg2, "save")) {
if(g_PropData[client].pendingSaveType == Save_Schematic) {
g_PropData[client].schematic.Save();
} else {
PrintToChat(client, "\x04[Editor]\x01 No schematic to save.");
}
} else {
PrintToChat(client, "\x04[Editor]\x01 Unknown option: %s", arg2);
}
} else if(StrEqual(arg, "list")) {
char arg2[16];
GetCmdArg(2, arg2, sizeof(arg2));

View file

@ -75,44 +75,89 @@ void AdminMenu_SaveLoad(TopMenu topmenu, TopMenuAction action, TopMenuObject obj
if(action == TopMenuAction_DisplayOption) {
Format(buffer, maxlength, "Save / Load");
} else if(action == TopMenuAction_SelectOption) {
Menu menu = new Menu(SaveLoadHandler);
menu.SetTitle("Save / Load");
char name[64];
// TODO: possibly let you overwrite saves?
menu.AddItem("", "[New Save]");
ArrayList saves = LoadSaves();
if(saves != null) {
for(int i = 0; i < saves.Length; i++) {
saves.GetString(i, name, sizeof(name));
menu.AddItem(name, name);
}
delete saves;
}
menu.ExitBackButton = true;
menu.ExitButton = true;
menu.Display(param, MENU_TIME_FOREVER);
Spawn_ShowSaveLoadMainMenu(param);
}
}
int SaveLoadHandler(Menu menu, MenuAction action, int client, int param2) {
int SaveLoadMainMenuHandler(Menu menu, MenuAction action, int client, int param2) {
if (action == MenuAction_Select) {
char info[2];
menu.GetItem(param2, info, sizeof(info));
SaveType type = view_as<SaveType>(StringToInt(info));
ShowSaves(client, type);
} else if (action == MenuAction_Cancel) {
if(param2 == MenuCancel_ExitBack) {
Spawn_ShowSaveLoadMainMenu(client);
}
} else if (action == MenuAction_End)
delete menu;
return 0;
}
int SaveLoadSceneHandler(Menu menu, MenuAction action, int client, int param2) {
if (action == MenuAction_Select) {
char saveName[64];
menu.GetItem(param2, saveName, sizeof(saveName));
if(saveName[0] == '\0') {
// Save new
FormatTime(saveName, sizeof(saveName), "%Y-%m-%d_%H-%I-%M");
if(CreateSave(saveName)) {
if(CreateSceneSave(saveName)) {
PrintToChat(client, "\x04[Editor]\x01 Saved as \x05%s/%s.txt", g_currentMap, saveName);
} else {
PrintToChat(client, "\x04[Editor]\x01 Unable to save. Sorry.");
}
} else if(LoadSave(saveName, true)) {
strcopy(g_pendingSaveName, sizeof(g_pendingSaveName), saveName);
} else if(g_pendingSaveClient != 0 && g_pendingSaveClient != client) {
PrintToChat(client, "\x04[Editor]\x01 Another user is currently loading a save.");
} else if(g_PropData[client].pendingSaveType == Save_Schematic) {
PrintToChat(client, "\x04[Editor]\x01 Please complete or cancel current schematic to continue.");
} else if(LoadScene(saveName, true)) {
ConfirmSave(client, saveName);
g_pendingSaveClient = client;
PrintToChat(client, "\x04[Editor]\x01 Previewing save \x05%s", saveName);
PrintToChat(client, "\x04[Editor]\x01 Press \x05Shift + Middle Mouse\x01 to spawn, \x05Middle Mouse\x01 to cancel");
} else {
PrintToChat(client, "\x04[Editor]\x01 Could not load save file.");
}
} else if (action == MenuAction_Cancel) {
if(param2 == MenuCancel_ExitBack) {
Spawn_ShowSaveLoadMainMenu(client);
}
} else if (action == MenuAction_End)
delete menu;
return 0;
}
int SaveLoadSchematicHandler(Menu menu, MenuAction action, int client, int param2) {
if (action == MenuAction_Select) {
char saveName[64];
menu.GetItem(param2, saveName, sizeof(saveName));
Schematic schem;
if(saveName[0] == '\0') {
if(g_PropData[client].pendingSaveType == Save_Schematic) {
if(g_PropData[client].schematic.Save()) {
PrintToChat(client, "\x04[Editor]\x01 Saved schematic as \x05%s", g_PropData[client].schematic.name);
} else {
PrintToChat(client, "\x04[Editor]\x01 Failed to save schematic.");
}
g_PropData[client].schematic.Reset();
g_PropData[client].pendingSaveType = Save_None;
} else {
g_PropData[client].chatPrompt = Prompt_SaveSchematic;
PrintToChat(client, "\x04[Editor]\x01 Enter in chat a name for schematic");
}
} else if(schem.Import(saveName)) {
float pos[3];
GetCursorLocation(client, pos);
ArrayList list = schem.SpawnEntities(pos, true);
SaveData save;
int parent = list.GetArray(0, save);
delete list;
Editor[client].Import(parent);
if(g_pendingSaveClient != 0 && g_pendingSaveClient != client) {
PrintToChat(client, "\x04[Editor]\x01 Another user is currently loading a save.");
PrintToChat(client, "\x04[Editor]\x01 Another user is currently loading a scene.");
} else {
g_pendingSaveClient = client;
PrintToChat(client, "\x04[Editor]\x01 Previewing save \x05%s", saveName);
PrintToChat(client, "\x04[Editor]\x01 Previewing schematic \x05%s", saveName);
PrintToChat(client, "\x04[Editor]\x01 Press \x05Shift + Middle Mouse\x01 to spawn, \x05Middle Mouse\x01 to cancel");
}
} else {
@ -120,12 +165,31 @@ int SaveLoadHandler(Menu menu, MenuAction action, int client, int param2) {
}
} else if (action == MenuAction_Cancel) {
if(param2 == MenuCancel_ExitBack) {
DisplayTopMenuCategory(g_topMenu, g_propSpawnerCategory, client);
Spawn_ShowSaveLoadMainMenu(client);
}
} else if (action == MenuAction_End)
delete menu;
return 0;
}
int SaveLoadConfirmHandler(Menu menu, MenuAction action, int client, int param2) {
if (action == MenuAction_Select) {
ClearSavePreview();
char info[64];
menu.GetItem(param2, info, sizeof(info));
if(info[0] != '\0') {
PrintToChat(client, "\x04[Editor]\x01 Loaded scene \x05%s", info);
LoadScene(info, false);
}
} else if (action == MenuAction_Cancel) {
if(param2 == MenuCancel_ExitBack) {
Spawn_ShowSaveLoadMainMenu(client);
}
} else if (action == MenuAction_End)
delete menu;
return 0;
}
int DeleteHandler(Menu menu, MenuAction action, int client, int param2) {
if (action == MenuAction_Select) {
char info[8];