Add project files.

master
sigonasr2 1 year ago
parent ec92e7683c
commit 65e1700014
  1. 31
      FiestaOnlineEditor.sln
  2. 7
      FiestaOnlineEditor/ActionIDs.h
  3. 141
      FiestaOnlineEditor/FiestaOnlineEditor.cpp
  4. 151
      FiestaOnlineEditor/FiestaOnlineEditor.vcxproj
  5. 54
      FiestaOnlineEditor/FiestaOnlineEditor.vcxproj.filters
  6. 7
      FiestaOnlineEditor/ItemEditor.cpp
  7. 8
      FiestaOnlineEditor/ItemEditor.h
  8. 34
      FiestaOnlineEditor/OpenFileDialog.cpp
  9. 13
      FiestaOnlineEditor/OpenFileDialog.h
  10. 535
      FiestaOnlineEditor/SHNFileDecryptor.h
  11. 8
      FiestaOnlineEditor/State.h
  12. BIN
      FiestaOnlineEditor/assets/RetroMenu.png
  13. 1
      FiestaOnlineEditor/assets/program.txt
  14. 602
      FiestaOnlineEditor/olcPGEX_PopupMenu.h
  15. 6697
      FiestaOnlineEditor/olcPixelGameEngine.h
  16. 435
      FiestaOnlineEditor/olcUTIL_DataFile.h

@ -0,0 +1,31 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.5.33516.290
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FiestaOnlineEditor", "FiestaOnlineEditor\FiestaOnlineEditor.vcxproj", "{75409DE7-0AB8-4CA1-B323-C6F433D8E13F}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{75409DE7-0AB8-4CA1-B323-C6F433D8E13F}.Debug|x64.ActiveCfg = Debug|x64
{75409DE7-0AB8-4CA1-B323-C6F433D8E13F}.Debug|x64.Build.0 = Debug|x64
{75409DE7-0AB8-4CA1-B323-C6F433D8E13F}.Debug|x86.ActiveCfg = Debug|Win32
{75409DE7-0AB8-4CA1-B323-C6F433D8E13F}.Debug|x86.Build.0 = Debug|Win32
{75409DE7-0AB8-4CA1-B323-C6F433D8E13F}.Release|x64.ActiveCfg = Release|x64
{75409DE7-0AB8-4CA1-B323-C6F433D8E13F}.Release|x64.Build.0 = Release|x64
{75409DE7-0AB8-4CA1-B323-C6F433D8E13F}.Release|x86.ActiveCfg = Release|Win32
{75409DE7-0AB8-4CA1-B323-C6F433D8E13F}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {CE193751-B8C3-43AF-82F7-C32FBD8BE5B7}
EndGlobalSection
EndGlobal

@ -0,0 +1,7 @@
#pragma once
enum ActionID{
RELOAD_FILE_DIALOG,
CHANGE_LOAD_PATH,
GO_BACK,
SELECTED_FOLDER,
};

@ -0,0 +1,141 @@
#define OLC_PGE_APPLICATION
#include "olcPixelGameEngine.h"
#define OLC_PGEX_POPUPMENU
#include "olcPGEX_PopupMenu.h"
#define OLC_PGEX_SHNFile
#include "SHNFileDecryptor.h"
#include "OpenFileDialog.h"
#include "ActionIDs.h"
#include "State.h"
#include "ItemEditor.h"
#include "olcUTIL_DataFile.h"
class FiestaOnlineEditor : public olc::PixelGameEngine
{
popup::Menu menu;
popup::Manager manager;
Sprite*sprMenu;
OpenFileDialog dialog;
std::list<std::string>selectedPath;
float lastPressedTime=0;
State appState=LOADFOLDER;
ItemEditor itemEditor;
utils::datafile config;
public:
FiestaOnlineEditor()
{
// Name your application
sAppName = "Fiesta Online Editor";
}
public:
bool OnUserCreate() override
{
menu.SetTable(1,6);
menu["Save"].Enable(false);
menu["Items"].SetTable(1,4).Enable(false);
menu["Items"]["Item Editor"];
menu["Items"]["Drop Groups"];
menu["Items"]["Icons"];
menu["Mobs"].Enable(false);
menu["Abilities"].Enable(false);
menu["Buffs"].Enable(false);
menu["Reload"].SetID(RELOAD_FILE_DIALOG);
menu.Build();
sprMenu = new Sprite("assets/RetroMenu.png");
selectedPath.push_back("");
utils::datafile::Read(config,"assets/program.txt");
if(config.HasProperty("DefaultPath")){
itemEditor.Load(config["DefaultPath"].GetString());
} else {
manager.Open(&dialog.GetMenu());
}
return true;
}
bool OnUserUpdate(float fElapsedTime) override
{
Clear(olc::VERY_DARK_GREEN);
lastPressedTime=std::max(0.f,lastPressedTime-fElapsedTime);
if (GetKey(UP).bHeld&&lastPressedTime==0){
if(GetKey(UP).bPressed){
lastPressedTime=0.2;
} else {
lastPressedTime=0.03;
}
manager.OnUp();
}
if (GetKey(DOWN).bHeld&&lastPressedTime==0){
if(GetKey(DOWN).bPressed){
lastPressedTime=0.2;
} else {
lastPressedTime=0.03;
}
manager.OnDown();
}
if (GetKey(LEFT).bHeld&&lastPressedTime==0){
if(GetKey(LEFT).bPressed){
lastPressedTime=0.2;
} else {
lastPressedTime=0.03;
}
manager.OnLeft();
}
if (GetKey(RIGHT).bHeld&&lastPressedTime==0){
if(GetKey(RIGHT).bPressed){
lastPressedTime=0.2;
} else {
lastPressedTime=0.03;
}
manager.OnRight();
}
if (GetKey(X).bPressed){
if(appState!=LOADFOLDER){
manager.OnBack();
}
}
if (GetKey(Z).bPressed){
popup::Menu*selected;
if((selected=manager.OnConfirm())!=nullptr){
std::string sLastAction =
"Selected: " + selected->GetName() +
" ID: " + std::to_string(selected->GetID());
std::cout<<sLastAction<<std::endl;
switch(selected->GetID()){
case RELOAD_FILE_DIALOG:{
}break;
case CHANGE_LOAD_PATH:{
selectedPath.push_back(selectedPath.back()+"/"+selected->GetName());
dialog.ChangePath(selectedPath.back());
manager.Open(&dialog.GetMenu());
}break;
case GO_BACK:{
selectedPath.pop_back();
dialog.ChangePath(selectedPath.back());
manager.Open(&dialog.GetMenu());
}break;
case SELECTED_FOLDER:{
std::cout<<selectedPath.back()<<std::endl;
config["DefaultPath"].SetString(selectedPath.back());
utils::datafile::Write(config,"assets/program.txt");
itemEditor.Load(selectedPath.back());
}break;
}
}
}
manager.Draw(sprMenu,{64,64});
return true;
}
};
int main()
{
FiestaOnlineEditor demo;
if (demo.Construct(960, 360, 2, 2))
demo.Start();
return 0;
}

@ -0,0 +1,151 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{75409de7-0ab8-4ca1-b323-c6f433d8e13f}</ProjectGuid>
<RootNamespace>FiestaOnlineEditor</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="ActionIDs.h" />
<ClInclude Include="ItemEditor.h" />
<ClInclude Include="olcPGEX_PopupMenu.h" />
<ClInclude Include="olcPixelGameEngine.h" />
<ClInclude Include="olcUTIL_DataFile.h" />
<ClInclude Include="OpenFileDialog.h" />
<ClInclude Include="SHNFileDecryptor.h" />
<ClInclude Include="State.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="FiestaOnlineEditor.cpp" />
<ClCompile Include="ItemEditor.cpp" />
<ClCompile Include="OpenFileDialog.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

@ -0,0 +1,54 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="SHNFileDecryptor.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="olcPGEX_PopupMenu.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="olcPixelGameEngine.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="OpenFileDialog.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="ActionIDs.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="State.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="ItemEditor.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="olcUTIL_DataFile.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="FiestaOnlineEditor.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="OpenFileDialog.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ItemEditor.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

@ -0,0 +1,7 @@
#include "ItemEditor.h"
ItemEditor::ItemEditor(){}
void ItemEditor::Load(std::string basePath){
ItemInfo.Load(basePath+"/ItemInfo.shn");
}

@ -0,0 +1,8 @@
#pragma once
#include "SHNFileDecryptor.h"
class ItemEditor{
SHNFile ItemInfo,ItemInfoServer,ItemViewInfo;
public:
ItemEditor();
void Load(std::string basePath);
};

@ -0,0 +1,34 @@
#include "OpenFileDialog.h"
#include "ActionIDs.h"
OpenFileDialog::OpenFileDialog(){
BuildMenu();
}
popup::Menu&OpenFileDialog::GetMenu(){
return menu;
}
void OpenFileDialog::ChangePath(std::string newPath){
if(newPath==""){
path="/"; //This is an edge case. We can't use the empty string to indicate a valid path.
} else {
path=newPath;
}
BuildMenu();
}
void OpenFileDialog::BuildMenu(){
menu.Clear();
menu["Select "+path].SetID(SELECTED_FOLDER);
menu[""].Enable(false);
if(path!="/"){
menu[".."].SetID(GO_BACK);
}
for(auto&dir:std::filesystem::directory_iterator(path)){
if(dir.is_directory()){
std::filesystem::path filename = dir.path().filename();
menu[filename.string()].SetID(CHANGE_LOAD_PATH);
}
}
menu.SetTable(1,std::min(20,menu.GetChildrenCount()));
menu.Build();
}

@ -0,0 +1,13 @@
#pragma once
#include "olcPGEX_PopupMenu.h"
#include <filesystem>
class OpenFileDialog{
popup::Menu menu;
std::string path="/";
public:
OpenFileDialog();
popup::Menu&GetMenu();
void ChangePath(std::string newPath);
void BuildMenu();
};

@ -0,0 +1,535 @@
#pragma once
#include <vector>
#include <cstddef>
#include <fstream>
#include <iostream>
#include <string>
#include <chrono>
#include <sstream>
//typedef std::std::byte std::byte;
typedef char sbyte;
class SHNFile{
std::vector<std::byte>ReadBytes(std::ifstream&file);
std::vector<std::byte>ReadBytes(std::ifstream&file,int bytes);
void WriteBytes(std::ofstream&file,std::vector<std::byte>&data);
int ReadInt32(std::ifstream&file);
void Encrypt();
void Decrypt();
std::vector<std::byte>&ReadBytes(int bytes);
std::byte ReadByte();
void WriteByte(std::ofstream&f,std::byte b);
void WriteSByte(std::ofstream&f,sbyte b);
uint16_t ReadUInt16();
void WriteUInt16(std::ofstream&f,uint16_t val);
int16_t ReadInt16();
void WriteInt16(std::ofstream&f,int16_t val);
uint32_t ReadUInt32();
void WriteUInt32(std::ofstream&f,uint32_t val);
int Read();
int32_t ReadInt32();
void WriteInt32(std::ofstream&f,int32_t val);
std::string ReadString(int bytes);
void WriteString(std::ofstream&f,std::string str,int bytes);
float ReadSingle();
void WriteSingle(std::ofstream&f,float n);
sbyte ReadSByte();
std::string ReadString();
uint32_t GetRecordLength();
public:
enum class DataType:int{
BYTE=1,
SBYTE=7,
UINT16=2,
INT16=6,
UINT32=3,
INT32=8,
FLOAT=4,
STRING=5
};
struct Data{
std::shared_ptr<void>data;
DataType type=DataType::BYTE;
Data(std::byte b);
Data(sbyte b);
Data(uint16_t n);
Data(int16_t n);
Data(uint32_t n);
Data(int32_t n);
Data(float n);
Data(std::string str);
template<typename T>
T Get();
template<typename T>
void Set(T b);
std::string GetDisplayText();
};
private:
friend std::ostream&operator<<(std::ostream&out,SHNFile::Data&d){
out<<d.GetDisplayText();
return out;
}
struct Column{
std::string name;
uint32_t type=0;
int length=0;
};
int marker=0;
std::vector<std::byte>cryptHeader;
std::vector<std::byte>data,rawData;
uint32_t header=0,recordCount=0,defaultRecordLength=0,columnCount=0;
std::vector<Column>columns;
std::vector<std::vector<Data>>contents;
std::string filename;
std::vector<std::byte>readArr;
std::byte*fileMarker=0;
public:
void Load(std::string file);
void Save();
void Write(int row,int col,std::byte val);
void Write(int row,int col,sbyte val);
void Write(int row,int col,int16_t val);
void Write(int row,int col,uint16_t val);
void Write(int row,int col,int32_t val);
void Write(int row,int col,uint32_t val);
void Write(int row,int col,float val);
void Write(int row,int col,std::string val);
const SHNFile::Data Get(int row,int col)const;
SHNFile();
};
#ifdef OLC_PGEX_SHNFile
std::vector<std::byte>SHNFile::ReadBytes(std::ifstream&file){
std::vector<std::byte>byteArr;
while(!file.eof()){
byteArr.push_back(std::byte(file.get()));
}
return byteArr;
}
std::vector<std::byte>SHNFile::ReadBytes(std::ifstream&file,int bytes){
std::vector<std::byte>byteArr;
for(int i=0;i<bytes;i++){
if(!file.eof()){
byteArr.push_back(std::byte(file.get()));
} else {
break;
}
}
return byteArr;
}
void SHNFile::WriteBytes(std::ofstream&file,std::vector<std::byte>&data){
for(int i=0;i<data.size();i++){
file<<unsigned char(data[i]);
}
}
int SHNFile::ReadInt32(std::ifstream&file){
std::vector<std::byte>intBytes=ReadBytes(file,4);
int numb = int(intBytes[3])<<24|int(intBytes[2])<<16|int(intBytes[1])<<8|int(intBytes[0]);
return numb;
}
void SHNFile::Encrypt(){
Decrypt();
}
void SHNFile::Decrypt(){
std::byte num = std::byte(data.size());
for(int i=data.size()-1;i>=0;i--){
data[i] = std::byte(data[i]^num);
std::byte num3 = std::byte(i);
num3 = std::byte(num3&std::byte(15));
num3 = std::byte(int(num3)+0x55);
num3 = std::byte(num3 ^ (std::byte((int(std::byte(i))*11))));
num3 = std::byte(num3^num);
num3 = std::byte(int(num3)^170);
num = num3;
}
}
std::vector<std::byte>&SHNFile::ReadBytes(int bytes){
readArr.clear();
std::copy(data.begin()+marker,data.begin()+marker+bytes,std::back_inserter(readArr));
marker+=bytes;
return readArr;
}
std::byte SHNFile::ReadByte(){
std::vector<std::byte>&b=ReadBytes(1);
if(b.size()>0){
return b[0];
} else {
return std::byte(0);
}
}
void SHNFile::WriteByte(std::ofstream&f,std::byte b){
f<<unsigned char(b);
}
void SHNFile::WriteSByte(std::ofstream&f,sbyte b){
f<<char(b);
}
uint16_t SHNFile::ReadUInt16(){
std::vector<std::byte>&intBytes=ReadBytes(2);
uint16_t numb = uint16_t(intBytes[1])<<8|uint16_t(intBytes[0]);
return numb;
}
void SHNFile::WriteUInt16(std::ofstream&f,uint16_t val){
f<<unsigned char(val&0xFF)<<unsigned char((val>>8)&0xFF);
}
int16_t SHNFile::ReadInt16(){
std::vector<std::byte>&intBytes=ReadBytes(2);
int16_t numb = int16_t(intBytes[1])<<8|int16_t(intBytes[0]);
return numb;
}
void SHNFile::WriteInt16(std::ofstream&f,int16_t val){
f<<unsigned char(val&0xFF)<<unsigned char((val>>8)&0xFF);
}
uint32_t SHNFile::ReadUInt32(){
std::vector<std::byte>&intBytes=ReadBytes(4);
uint32_t numb = uint32_t(intBytes[3])<<24|uint32_t(intBytes[2])<<16|uint32_t(intBytes[1])<<8|uint32_t(intBytes[0]);
return numb;
}
void SHNFile::WriteUInt32(std::ofstream&f,uint32_t val){
f<<unsigned char(val&0xFF)<<unsigned char((val>>8)&0xFF)<<unsigned char((val>>16)&0xFF)<<unsigned char((val>>24)&0xFF);
}
int SHNFile::Read(){
std::vector<std::byte>&intBytes=ReadBytes(4);
int numb = int(intBytes[3])<<24|int(intBytes[2])<<16|int(intBytes[1])<<8|int(intBytes[0]);
return numb;
}
int32_t SHNFile::ReadInt32(){
std::vector<std::byte>&intBytes=ReadBytes(4);
int32_t numb = int32_t(intBytes[3])<<24|int32_t(intBytes[2])<<16|int32_t(intBytes[1])<<8|uint32_t(intBytes[0]);
return numb;
}
void SHNFile::WriteInt32(std::ofstream&f,int32_t val){
f<<unsigned char(val&0xFF)<<unsigned char((val>>8)&0xFF)<<unsigned char((val>>16)&0xFF)<<unsigned char((val>>24)&0xFF);
}
std::string SHNFile::ReadString(int bytes){
std::vector<std::byte>&strBytes=ReadBytes(bytes);
std::string str="";
for(int i=0;i<strBytes.size();i++){
if(strBytes[i]!=std::byte(0)){
str+=unsigned char(strBytes[i]);
}
}
return str;
}
void SHNFile::WriteString(std::ofstream&f,std::string str,int bytes){
for(int i=0;i<bytes;i++){
if(i<str.length()){
f<<unsigned char(str[i]);
} else {
f<<unsigned char(0x00);
}
}
if(bytes==-1){
//We use this to append a 0 for unknown length strings (of the shn file)
f<<unsigned char(0x00);
}
}
float SHNFile::ReadSingle(){
std::vector<std::byte>strBytes=ReadBytes(4);
std::byte bytes[]={strBytes[0],strBytes[1],strBytes[2],strBytes[3]};
float f;
memcpy(&f,&bytes,4);
return f;
}
void SHNFile::WriteSingle(std::ofstream&f,float n){
std::byte bytes[4]={};
memcpy(&n,&bytes,4);
for(int i=0;i<4;i++){
f<<unsigned char(bytes[i]);
}
}
sbyte SHNFile::ReadSByte(){
return sbyte(ReadBytes(1)[0]);
}
std::string SHNFile::ReadString(){
std::string str="";
while(true){
std::vector<std::byte>byteArr=ReadBytes(1);
if(byteArr.size()>0&&byteArr[0]!=std::byte(0)){
str+=unsigned char(byteArr[0]);
}else{
break;
}
}
return str;
}
uint32_t SHNFile::GetRecordLength(){
uint32_t start=2;
for(Column&col:columns){
start+=uint32_t(col.length);
}
return start;
}
SHNFile::Data::Data(std::byte b){
std::shared_ptr<std::byte>ptr=std::make_shared<std::byte>(std::byte(b));
data=ptr;
type=DataType::BYTE;
}
SHNFile::Data::Data(sbyte b){
std::shared_ptr<sbyte>ptr=std::make_shared<sbyte>(sbyte(b));
data=ptr;
type=DataType::SBYTE;
}
SHNFile::Data::Data(uint16_t n){
std::shared_ptr<uint16_t>ptr=std::make_shared<uint16_t>(uint16_t(n));
data=ptr;
type=DataType::UINT16;
}
SHNFile::Data::Data(int16_t n){
std::shared_ptr<int16_t>ptr=std::make_shared<int16_t>(int16_t(n));
data=ptr;
type=DataType::INT16;
}
SHNFile::Data::Data(uint32_t n){
std::shared_ptr<uint32_t>ptr=std::make_shared<uint32_t>(uint32_t(n));
data=ptr;
type=DataType::UINT32;
}
SHNFile::Data::Data(int32_t n){
std::shared_ptr<int32_t>ptr=std::make_shared<int32_t>(int32_t(n));
data=ptr;
type=DataType::INT32;
}
SHNFile::Data::Data(float n){
std::shared_ptr<float>ptr=std::make_shared<float>(float(n));
data=ptr;
type=DataType::FLOAT;
}
SHNFile::Data::Data(std::string str){
std::shared_ptr<std::string>ptr=std::make_shared<std::string>(str);
data=ptr;
type=DataType::STRING;
}
template <typename T>
T SHNFile::Data::Get(){
return *std::static_pointer_cast<T>(data);
}
template<typename T>
void SHNFile::Data::Set(T b){
data=std::make_shared<T>(b);
}
std::string SHNFile::Data::GetDisplayText(){
switch(type){
case DataType::BYTE:{
return std::to_string(int(Get<std::byte>()));
}break;
case DataType::SBYTE:{
return std::to_string(int(Get<sbyte>()));
}break;
case DataType::UINT16:{
return std::to_string(Get<uint16_t>());
}break;
case DataType::INT16:{
return std::to_string(Get<int16_t>());
}break;
case DataType::UINT32:{
return std::to_string(Get<uint32_t>());
}break;
case DataType::INT32:{
return std::to_string(Get<int32_t>());
}break;
case DataType::FLOAT:{
return std::to_string(Get<float>());
}break;
case DataType::STRING:{
return Get<std::string>();
}break;
}
}
void SHNFile::Load(std::string file){
header=recordCount=defaultRecordLength=columnCount=0;
columns.clear();
contents.clear();
rawData.clear();
marker=0;
std::chrono::time_point<std::chrono::high_resolution_clock>timer=std::chrono::high_resolution_clock::now();
filename=file;
//FILE OPERATIONS!
std::ifstream f(filename,std::ios::binary);
//Since we don't just read in the entire file raw, we have to do some additional work here as the header provides us with some basic info on how to decrypt this file.
//The backup itself needs all the data from the original file, so we're appending it to rawData as we continue reading it.
cryptHeader=ReadBytes(f,0x20);
int readAmt=ReadInt32(f);
rawData.push_back(std::byte(readAmt&0xFF));
rawData.push_back(std::byte((readAmt>>8)&0xFF));
rawData.push_back(std::byte((readAmt>>16)&0xFF));
rawData.push_back(std::byte((readAmt>>24)&0xFF));
data=ReadBytes(f,readAmt-0x24);
std::copy(data.begin(),data.end(),std::back_inserter(rawData));
Decrypt();
header=ReadUInt32();
recordCount=ReadUInt32();
defaultRecordLength=ReadUInt32();
columnCount=ReadUInt32();
int num2=2;
for(int i=0;i<columnCount;i++){
Column columnData;
columnData.name=ReadString(0x30);
columnData.type=ReadUInt32();
columnData.length=ReadInt32();
num2+=columnData.length;
columns.push_back(columnData);
}
for(int i=0;i<recordCount;i++){
ReadUInt16();
std::vector<Data>row;
for(int j=0;j<columns.size();j++){
switch(columns[j].type){
case 1:
case 12:
case 0x10:{
row.push_back(ReadByte());
}break;
case 2:{
row.push_back(ReadUInt16());
}break;
case 3:
case 11:
case 0x12:
case 0x1b:{
row.push_back(ReadUInt32());
}break;
case 5:{
row.push_back(ReadSingle());
}break;
case 9:
case 0x18:{
row.push_back(ReadString(columns[j].length));
}break;
case 13:
case 0x15:{
row.push_back(ReadInt16());
}break;
case 20:{
row.push_back(ReadSByte());
}break;
case 0x16:{
row.push_back(ReadInt32());
}break;
case 0x1a:{
row.push_back(ReadString());
}break;
}
}
contents.push_back(row);
}
std::chrono::duration<float>dur=std::chrono::high_resolution_clock::now()-timer;
std::cout<<"Loaded "<<contents.size()<<" rows, "<<contents.size()*columnCount<<" columns, "<<dur.count()<<"s"<<std::endl;
}
void SHNFile::Save(){
std::ofstream fBackup(filename+".bak",std::ios::binary);
std::cout<<"Saving a backup to "<<filename+".bak"<<std::endl;
for(int i=0;i<rawData.size();i++){
fBackup<<unsigned char(rawData[i]);
}
/*//Decoded version only required for debugging.
std::ofstream fDecodedBackup(filename+"_decoded.bak",std::ios::binary);
std::cout<<"Saving a backup to "<<filename+"_decoded.bak"<<std::endl;
for(int i=0;i<data.size();i++){
fDecodedBackup<<unsigned char(data[i]);
}*/
std::cout<<"Saving new file..."<<std::endl;
std::ofstream f(filename,std::ios::binary);
WriteUInt32(f,header);
WriteUInt32(f,contents.size());
WriteUInt32(f,GetRecordLength());
WriteUInt32(f,columnCount);
for(int i=0;i<columnCount;i++){
WriteString(f,columns[i].name,0x30);
WriteUInt32(f,columns[i].type);
WriteInt32(f,columns[i].length);
}
for(std::vector<Data>&row:contents){
std::streampos marker = f.tellp();
WriteUInt16(f,uint16_t(0));
int colNum=0;
for(Data&col:row){
switch(columns[colNum].type){
case 1:
case 12:
case 0x10:{
WriteByte(f,col.Get<std::byte>());
}break;
case 2:{
WriteUInt16(f,col.Get<uint16_t>());
}break;
case 3:
case 11:
case 0x12:
case 0x1b:{
WriteUInt32(f,col.Get<uint32_t>());
}break;
case 5:{
WriteSingle(f,col.Get<float>());
}break;
case 9:
case 0x18:{
WriteString(f,std::string(col.Get<std::string>()),columns[colNum].length);
}break;
case 13:
case 0x15:{
WriteInt16(f,col.Get<uint16_t>());
}break;
case 20:{
WriteSByte(f,col.Get<sbyte>());
}break;
case 0x16:{
WriteInt32(f,col.Get<int32_t>());
}break;
case 0x1a:{
WriteString(f,col.Get<std::string>(),-1);
}break;
}
colNum++;
}
std::streampos offset = f.tellp() - marker;
std::streampos newMarker = f.tellp();
f.seekp(marker);
WriteUInt16(f,uint16_t(offset));
f.seekp(newMarker);
}
f.close();
std::ifstream finishedFile(filename,std::ios::binary);
data=ReadBytes(finishedFile);
std::ofstream encryptedFile(filename,std::ios::binary);
std::cout<<"Encrypting..."<<std::endl;
Encrypt();
WriteBytes(encryptedFile,cryptHeader);
WriteInt32(encryptedFile,int32_t(data.size()+0x24));
WriteBytes(encryptedFile,data);
std::cout<<"File "<<filename<<" Saved!"<<std::endl;
}
const SHNFile::Data SHNFile::Get(int row,int col)const{
return contents[row][col];
};
void SHNFile::Write(int row,int col,std::byte val){
contents[row][col].Set<std::byte>(val);
}
void SHNFile::Write(int row,int col,sbyte val){
contents[row][col].Set<sbyte>(val);
}
void SHNFile::Write(int row,int col,int16_t val){
contents[row][col].Set<int16_t>(val);
}
void SHNFile::Write(int row,int col,uint16_t val){
contents[row][col].Set<uint16_t>(val);
}
void SHNFile::Write(int row,int col,int32_t val){
contents[row][col].Set<int32_t>(val);
}
void SHNFile::Write(int row,int col,uint32_t val){
contents[row][col].Set<uint32_t>(val);
}
void SHNFile::Write(int row,int col,float val){
contents[row][col].Set<float>(val);
}
void SHNFile::Write(int row,int col,std::string val){
contents[row][col].Set<std::string>(val);
}
SHNFile::SHNFile(){
readArr.reserve(64000);
}
#endif

@ -0,0 +1,8 @@
#pragma once
enum State{
LOADFOLDER,
ITEMEDIT,
MOBEDIT,
QUESTEDIT,
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

@ -0,0 +1 @@
DefaultPath = /Users/sigon/Documents/NA2016-main/Server/9Data/Shine

@ -0,0 +1,602 @@
/*
olcPGEX_PopUp.h
+-------------------------------------------------------------+
| OneLoneCoder Pixel Game Engine Extension |
| Retro PopUp Menu 1.0 |
+-------------------------------------------------------------+
What is this?
~~~~~~~~~~~~~
This is an extension to the olcPixelGameEngine, which provides
a quick and easy to use, flexible, skinnable context pop-up
menu system.
License (OLC-3)
~~~~~~~~~~~~~~~
Copyright 2018 - 2020 OneLoneCoder.com
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions or derivations of source code must retain the above
copyright notice, this list of conditions and the following disclaimer.
2. Redistributions or derivative works in binary form must reproduce
the above copyright notice. This list of conditions and the following
disclaimer must be reproduced in the documentation and/or other
materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Links
~~~~~
YouTube: https://www.youtube.com/javidx9
Discord: https://discord.gg/WhwHUMV
Twitter: https://www.twitter.com/javidx9
Twitch: https://www.twitch.tv/javidx9
GitHub: https://www.github.com/onelonecoder
Homepage: https://www.onelonecoder.com
Author
~~~~~~
David Barr, aka javidx9, ©OneLoneCoder 2019, 2020
*/
/*
Example
~~~~~~~
#define OLC_PGEX_POPUPMENU
#include "olcPGEX_PopUpMenu.h"
NOTE: Requires a 9-patch sprite, by default each patch is
8x8 pixels, patches are as follows:
| PANEL TL | PANEL T | PANEL TR | SCROLL UP | CURSOR TL | CURSOR TR |
| PANEL L | PANEL M | PANEL R | SUBMENU | CURSOR BL | CURSOR BR |
| PANEL BL | PANEL B | PANEL BR | SCROLL DOWN | UNUSED | UNUSED |
You can find an example sprite here:
https://github.com/OneLoneCoder/olcPixelGameEngine/blob/master/Videos/RetroMenu.png
Constructing A Menu
~~~~~~~~~~~~~~~~~~~
// Declaration (presumably inside class)
olc::popup::Menu m;
// Construction (root menu is a 1x5 table)
m.SetTable(1, 5);
// Add first item to root menu (A 1x5 submenu)
m["Menu1"].SetTable(1, 5);
// Add items to first item
m["Menu1"]["Item1"];
m["Menu1"]["Item2"];
// Add a 4x3 submenu
m["Menu1"]["Item3"].SetTable(4, 3);
m["Menu1"]["Item3"]["Option1"];
m["Menu1"]["Item3"]["Option2"];
// Set properties of specific item
m["Menu1"]["Item3"]["Option3"].Enable(false);
m["Menu1"]["Item3"]["Option4"];
m["Menu1"]["Item3"]["Option5"];
m["Menu1"]["Item4"];
// Add second item to root menu
m["Menu2"].SetTable(3, 3);
m["Menu2"]["Item1"];
m["Menu2"]["Item2"].SetID(1001).Enable(true);
m["Menu2"]["Item3"];
// Construct the menu structure
m.Build();
Displaying a Menu
~~~~~~~~~~~~~~~~~
// Declaration of menu manager (presumably inside class)
olc::popup::Manager man;
// Set the Menu object to the MenuManager (call once per pop)
man.Open(&m);
// Draw Menu at position (30, 30), using "patch sprite"
man.Draw(sprGFX, { 30,30 });
Interacting with menu
~~~~~~~~~~~~~~~~~~~~~
// Send key events to menu
if (GetKey(olc::Key::UP).bPressed) man.OnUp();
if (GetKey(olc::Key::DOWN).bPressed) man.OnDown();
if (GetKey(olc::Key::LEFT).bPressed) man.OnLeft();
if (GetKey(olc::Key::RIGHT).bPressed) man.OnRight();
if (GetKey(olc::Key::Z).bPressed) man.OnBack();
// "Confirm/Action" Key does something, if it returns non-null
// then a menu item has been selected. The specific item will
// be returned
olc::popup::Menu* command = nullptr;
if (GetKey(olc::Key::SPACE).bPressed) command = man.OnConfirm();
if (command != nullptr)
{
std::string sLastAction =
"Selected: " + command->GetName() +
" ID: " + std::to_string(command->GetID());
// Optionally close menu?
man.Close();
}
*/
#ifndef OLC_PGEX_POPUPMENU_H
#define OLC_PGEX_POPUPMENU_H
#include "olcPixelGameEngine.h"
#include <cstdint>
namespace olc
{
namespace popup
{
constexpr int32_t nPatch = 8;
class Menu
{
public:
Menu();
Menu(const std::string n);
Menu& SetTable(int32_t nColumns, int32_t nRows);
Menu& SetID(int32_t id);
Menu& Enable(bool b);
int32_t GetID();
std::string& GetName();
bool Enabled();
bool HasChildren();
int GetChildrenCount();
olc::vi2d GetSize();
olc::vi2d& GetCursorPosition();
Menu& operator[](const std::string& name);
void Build();
void DrawSelf(olc::PixelGameEngine& pge, olc::Sprite* sprGFX, olc::vi2d vScreenOffset);
void ClampCursor();
void Clear();
void OnUp();
void OnDown();
void OnLeft();
void OnRight();
Menu* OnConfirm();
Menu* GetSelectedItem();
protected:
int32_t nID = -1;
olc::vi2d vCellTable = { 1, 0 };
std::unordered_map<std::string, size_t> itemPointer;
std::vector<olc::popup::Menu> items;
olc::vi2d vSizeInPatches = { 0, 0 };
olc::vi2d vCellSize = { 0, 0 };
olc::vi2d vCellPadding = { 2, 0 };
olc::vi2d vCellCursor = { 0, 0 };
int32_t nCursorItem = 0;
int32_t nTopVisibleRow = 0;
int32_t nTotalRows = 0;
const olc::vi2d vPatchSize = { nPatch, nPatch };
std::string sName;
olc::vi2d vCursorPos = { 0, 0 };
bool bEnabled = true;
};
class Manager : public olc::PGEX
{
public:
Manager();
void Open(Menu* mo);
void Close();
void OnUp();
void OnDown();
void OnLeft();
void OnRight();
void OnBack();
Menu* OnConfirm();
void Draw(olc::Sprite* sprGFX, olc::vi2d vScreenOffset);
private:
std::list<Menu*> panels;
};
}
};
#ifdef OLC_PGEX_POPUPMENU
#undef OLC_PGEX_POPUPMENU
namespace olc
{
namespace popup
{
Menu::Menu()
{
}
Menu::Menu(const std::string n)
{
sName = n;
}
Menu& Menu::SetTable(int32_t nColumns, int32_t nRows)
{
vCellTable = { nColumns, nRows };
return *this;
}
Menu& Menu::SetID(int32_t id)
{
nID = id;
return *this;
}
Menu& Menu::Enable(bool b)
{
bEnabled = b;
return *this;
}
int32_t Menu::GetID()
{
return nID;
}
std::string& Menu::GetName()
{
return sName;
}
bool Menu::Enabled()
{
return bEnabled;
}
bool Menu::HasChildren()
{
return !items.empty();
}
int Menu::GetChildrenCount()
{
return items.size();
}
olc::vi2d Menu::GetSize()
{
return { int32_t(sName.size()), 1 };
}
olc::vi2d& Menu::GetCursorPosition()
{
return vCursorPos;
}
Menu& Menu::operator[](const std::string& name)
{
if (itemPointer.count(name) == 0)
{
itemPointer[name] = items.size();
items.push_back(Menu(name));
}
return items[itemPointer[name]];
}
void Menu::Clear(){
items.clear();
itemPointer.clear();
vCursorPos=vCellCursor={0,0};
nTopVisibleRow=0;
nCursorItem=0;
Build(); //Tidy up the new empty menu.
}
void Menu::Build()
{
// Recursively build all children, so they can determine their size, use
// that size to indicate cell sizes if this object contains more than
// one item
for (auto& m : items)
{
if (m.HasChildren())
{
m.Build();
}
// Longest child name determines cell width
vCellSize.x = std::max(m.GetSize().x, vCellSize.x);
vCellSize.y = std::max(m.GetSize().y, vCellSize.y);
}
// Adjust size of this object (in patches) if it were rendered as a panel
vSizeInPatches.x = vCellTable.x * vCellSize.x + (vCellTable.x - 1) * vCellPadding.x + 2;
vSizeInPatches.y = vCellTable.y * vCellSize.y + (vCellTable.y - 1) * vCellPadding.y + 2;
// Calculate how many rows this item has to hold
nTotalRows = (items.size() / vCellTable.x) + (((items.size() % vCellTable.x) > 0) ? 1 : 0);
}
void Menu::DrawSelf(olc::PixelGameEngine& pge, olc::Sprite* sprGFX, olc::vi2d vScreenOffset)
{
// === Draw Panel
// Record current pixel mode user is using
olc::Pixel::Mode currentPixelMode = pge.GetPixelMode();
pge.SetPixelMode(olc::Pixel::MASK);
// Draw Panel & Border
olc::vi2d vPatchPos = { 0,0 };
for (vPatchPos.x = 0; vPatchPos.x < vSizeInPatches.x; vPatchPos.x++)
{
for (vPatchPos.y = 0; vPatchPos.y < vSizeInPatches.y; vPatchPos.y++)
{
// Determine position in screen space
olc::vi2d vScreenLocation = vPatchPos * nPatch + vScreenOffset;
// Calculate which patch is needed
olc::vi2d vSourcePatch = { 0, 0 };
if (vPatchPos.x > 0) vSourcePatch.x = 1;
if (vPatchPos.x == vSizeInPatches.x - 1) vSourcePatch.x = 2;
if (vPatchPos.y > 0) vSourcePatch.y = 1;
if (vPatchPos.y == vSizeInPatches.y - 1) vSourcePatch.y = 2;
// Draw Actual Patch
pge.DrawPartialSprite(vScreenLocation, sprGFX, vSourcePatch * nPatch, vPatchSize);
}
}
// === Draw Panel Contents
olc::vi2d vCell = { 0,0 };
vPatchPos = { 1,1 };
// Work out visible items
int32_t nTopLeftItem = nTopVisibleRow * vCellTable.x;
int32_t nBottomRightItem = vCellTable.y * vCellTable.x + nTopLeftItem;
// Clamp to size of child item vector
nBottomRightItem = std::min(int32_t(items.size()), nBottomRightItem);
int32_t nVisibleItems = nBottomRightItem - nTopLeftItem;
// Draw Scroll Markers (if required)
if (nTopVisibleRow > 0)
{
vPatchPos = { vSizeInPatches.x - 2, 0 };
olc::vi2d vScreenLocation = vPatchPos * nPatch + vScreenOffset;
olc::vi2d vSourcePatch = { 3, 0 };
pge.DrawPartialSprite(vScreenLocation, sprGFX, vSourcePatch * nPatch, vPatchSize);
}
if ((nTotalRows - nTopVisibleRow) > vCellTable.y)
{
vPatchPos = { vSizeInPatches.x - 2, vSizeInPatches.y - 1 };
olc::vi2d vScreenLocation = vPatchPos * nPatch + vScreenOffset;
olc::vi2d vSourcePatch = { 3, 2 };
pge.DrawPartialSprite(vScreenLocation, sprGFX, vSourcePatch * nPatch, vPatchSize);
}
// Draw Visible Items
for (int32_t i = 0; i < nVisibleItems; i++)
{
// Cell location
vCell.x = i % vCellTable.x;
vCell.y = i / vCellTable.x;
// Patch location (including border offset and padding)
vPatchPos.x = vCell.x * (vCellSize.x + vCellPadding.x) + 1;
vPatchPos.y = vCell.y * (vCellSize.y + vCellPadding.y) + 1;
// Actual screen location in pixels
olc::vi2d vScreenLocation = vPatchPos * nPatch + vScreenOffset;
// Display Item Header
pge.DrawString(vScreenLocation, items[nTopLeftItem + i].sName, items[nTopLeftItem + i].bEnabled ? olc::WHITE : olc::DARK_GREY);
if (items[nTopLeftItem + i].HasChildren())
{
// Display Indicator that panel has a sub panel
vPatchPos.x = vCell.x * (vCellSize.x + vCellPadding.x) + 1 + vCellSize.x;
vPatchPos.y = vCell.y * (vCellSize.y + vCellPadding.y) + 1;
olc::vi2d vSourcePatch = { 3, 1 };
vScreenLocation = vPatchPos * nPatch + vScreenOffset;
pge.DrawPartialSprite(vScreenLocation, sprGFX, vSourcePatch * nPatch, vPatchSize);
}
}
// Calculate cursor position in screen space in case system draws it
vCursorPos.x = (vCellCursor.x * (vCellSize.x + vCellPadding.x)) * nPatch + vScreenOffset.x - nPatch;
vCursorPos.y = ((vCellCursor.y - nTopVisibleRow) * (vCellSize.y + vCellPadding.y)) * nPatch + vScreenOffset.y + nPatch;
}
void Menu::ClampCursor()
{
// Find item in children
nCursorItem = vCellCursor.y * vCellTable.x + vCellCursor.x;
// Clamp Cursor
if (nCursorItem >= int32_t(items.size()))
{
vCellCursor.y = (items.size() / vCellTable.x);
vCellCursor.x = (items.size() % vCellTable.x) - 1;
nCursorItem = items.size() - 1;
}
}
void Menu::OnUp()
{
vCellCursor.y--;
if (vCellCursor.y < 0) vCellCursor.y = 0;
if (vCellCursor.y < nTopVisibleRow)
{
nTopVisibleRow--;
if (nTopVisibleRow < 0) nTopVisibleRow = 0;
}
ClampCursor();
}
void Menu::OnDown()
{
vCellCursor.y++;
if (vCellCursor.y == nTotalRows) vCellCursor.y = nTotalRows - 1;
if (vCellCursor.y > (nTopVisibleRow + vCellTable.y - 1))
{
nTopVisibleRow++;
if (nTopVisibleRow > (nTotalRows - vCellTable.y))
nTopVisibleRow = nTotalRows - vCellTable.y;
}
ClampCursor();
}
void Menu::OnLeft()
{
vCellCursor.x--;
if (vCellCursor.x < 0) vCellCursor.x = 0;
ClampCursor();
}
void Menu::OnRight()
{
vCellCursor.x++;
if (vCellCursor.x == vCellTable.x) vCellCursor.x = vCellTable.x - 1;
ClampCursor();
}
Menu* Menu::OnConfirm()
{
// Check if selected item has children
if (items[nCursorItem].HasChildren())
{
return &items[nCursorItem];
}
else
return this;
}
Menu* Menu::GetSelectedItem()
{
return &items[nCursorItem];
}
// =====================================================================
Manager::Manager()
{
}
void Manager::Open(Menu* mo)
{
Close();
panels.push_back(mo);
}
void Manager::Close()
{
panels.clear();
}
void Manager::OnUp()
{
if (!panels.empty()) panels.back()->OnUp();
}
void Manager::OnDown()
{
if (!panels.empty()) panels.back()->OnDown();
}
void Manager::OnLeft()
{
if (!panels.empty()) panels.back()->OnLeft();
}
void Manager::OnRight()
{
if (!panels.empty()) panels.back()->OnRight();
}
void Manager::OnBack()
{
if (!panels.empty()) panels.pop_back();
}
Menu* Manager::OnConfirm()
{
if (panels.empty()) return nullptr;
Menu* next = panels.back()->OnConfirm();
if (next == panels.back())
{
if (panels.back()->GetSelectedItem()->Enabled())
return panels.back()->GetSelectedItem();
}
else
{
if (next->Enabled())
panels.push_back(next);
}
return nullptr;
}
void Manager::Draw(olc::Sprite* sprGFX, olc::vi2d vScreenOffset)
{
if (panels.empty()) return;
// Draw Visible Menu System
for (auto& p : panels)
{
p->DrawSelf(*pge, sprGFX, vScreenOffset);
vScreenOffset += {10, 10};
}
// Draw Cursor
olc::Pixel::Mode currentPixelMode = pge->GetPixelMode();
pge->SetPixelMode(olc::Pixel::ALPHA);
pge->DrawPartialSprite(panels.back()->GetCursorPosition(), sprGFX, olc::vi2d(4, 0) * nPatch, { nPatch * 2, nPatch * 2 });
pge->SetPixelMode(currentPixelMode);
}
}
};
#endif
#endif

File diff suppressed because it is too large Load Diff

@ -0,0 +1,435 @@
/*
OneLoneCoder - DataFile v1.00
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
An "easy to use" serialisation/deserialisation class that yields
human readable hierachical files.
License (OLC-3)
~~~~~~~~~~~~~~~
Copyright 2018 - 2022 OneLoneCoder.com
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions or derivations of source code must retain the above
copyright notice, this list of conditions and the following disclaimer.
2. Redistributions or derivative works in binary form must reproduce
the above copyright notice. This list of conditions and the following
disclaimer must be reproduced in the documentation and/or other
materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Links
~~~~~
YouTube: https://www.youtube.com/javidx9
Discord: https://discord.gg/WhwHUMV
Twitter: https://www.twitter.com/javidx9
Twitch: https://www.twitch.tv/javidx9
GitHub: https://www.github.com/onelonecoder
Homepage: https://www.onelonecoder.com
Author
~~~~~~
David Barr, aka javidx9, <EFBFBD>OneLoneCoder 2019, 2020, 2021, 2022
*/
#pragma once
#include <iostream>
#include <string>
#include <unordered_map>
#include <functional>
#include <fstream>
#include <stack>
#include <sstream>
namespace olc::utils
{
class datafile
{
public:
inline datafile() = default;
public:
// Sets the String Value of a Property (for a given index)
inline void SetString(const std::string& sString, const size_t nItem = 0)
{
if (nItem >= m_vContent.size())
m_vContent.resize(nItem + 1);
m_vContent[nItem] = sString;
}
// Retrieves the String Value of a Property (for a given index) or ""
inline const std::string GetString(const size_t nItem = 0) const
{
if (nItem >= m_vContent.size())
return "";
else
return m_vContent[nItem];
}
// Retrieves the Real Value of a Property (for a given index) or 0.0
inline const double GetReal(const size_t nItem = 0) const
{
return std::atof(GetString(nItem).c_str());
}
// Sets the Real Value of a Property (for a given index)
inline void SetReal(const double d, const size_t nItem = 0)
{
SetString(std::to_string(d), nItem);
}
// Retrieves the Integer Value of a Property (for a given index) or 0
inline const int32_t GetInt(const size_t nItem = 0) const
{
return std::atoi(GetString(nItem).c_str());
}
// Sets the Integer Value of a Property (for a given index)
inline void SetInt(const int32_t n, const size_t nItem = 0)
{
SetString(std::to_string(n), nItem);
}
// Returns the number of Values a property consists of
inline size_t GetValueCount() const
{
return m_vContent.size();
}
// Checks if a property exists - useful to avoid creating properties
// via reading them, though non-essential
inline bool HasProperty(const std::string& sName) const
{
return m_mapObjects.count(sName) > 0;
}
// Access a datafile via a convenient name - "root.node.something.property"
inline datafile& GetProperty(const std::string& name)
{
size_t x = name.find_first_of('.');
if (x != std::string::npos)
{
std::string sProperty = name.substr(0, x);
if (HasProperty(sProperty))
return operator[](sProperty).GetProperty(name.substr(x + 1, name.size()));
else
return operator[](sProperty);
}
else
{
return operator[](name);
}
}
// Access a numbered element - "node[23]", or "root[56].node"
inline datafile& GetIndexedProperty(const std::string& name, const size_t nIndex)
{
return GetProperty(name + "[" + std::to_string(nIndex) + "]");
}
public:
// Writes a "datafile" node (and all of its child nodes and properties) recursively
// to a file.
inline static bool Write(const datafile& n, const std::string& sFileName, const std::string& sIndent = "\t", const char sListSep = ',')
{
// Cache indentation level
size_t nIndentCount = 0;
// Cache sperator string for convenience
std::string sSeperator = std::string(1, sListSep) + " ";
// Fully specified lambda, because this lambda is recursive!
std::function<void(const datafile&, std::ofstream&)> write = [&](const datafile& n, std::ofstream& file)
{
// Lambda creates string given indentation preferences
auto indent = [&](const std::string& sString, const size_t nCount)
{
std::string sOut;
for (size_t n = 0; n < nCount; n++) sOut += sString;
return sOut;
};
// Iterate through each property of this node
for (auto const& property : n.m_vecObjects)
{
// Does property contain any sub objects?
if (property.second.m_vecObjects.empty())
{
// No, so it's an assigned field and should just be written. If the property
// is flagged as comment, it has no assignment potential. First write the
// property name
file << indent(sIndent, nIndentCount) << property.first << (property.second.m_bIsComment ? "" : " = ");
// Second, write the property value (or values, seperated by provided
// separation charater
size_t nItems = property.second.GetValueCount();
for (size_t i = 0; i < property.second.GetValueCount(); i++)
{
// If the Value being written, in string form, contains the separation
// character, then the value must be written inside quotation marks. Note,
// that if the Value is the last of a list of Values for a property, it is
// not suffixed with the separator
size_t x = property.second.GetString(i).find_first_of(sListSep);
if (x != std::string::npos)
{
// Value contains separator, so wrap in quotes
file << "\"" << property.second.GetString(i) << "\"" << ((nItems > 1) ? sSeperator : "");
}
else
{
// Value does not contain separator, so just write out
file << property.second.GetString(i) << ((nItems > 1) ? sSeperator : "");
}
nItems--;
}
// Property written, move to next line
file << "\n";
}
else
{
// Yes, property has properties of its own, so it's a node
// Force a new line and write out the node's name
file << "\n" << indent(sIndent, nIndentCount) << property.first << "\n";
// Open braces, and update indentation
file << indent(sIndent, nIndentCount) << "{\n";
nIndentCount++;
// Recursively write that node
write(property.second, file);
// Node written, so close braces
file << indent(sIndent, nIndentCount) << "}\n\n";
}
}
// We've finished writing out a node, regardless of state, our indentation
// must decrease, unless we're top level
if (nIndentCount > 0) nIndentCount--;
};
// Start Here! Open the file for writing
std::ofstream file(sFileName);
if (file.is_open())
{
// Write the file starting form the supplied node
write(n, file);
return true;
}
return false;
}
inline static bool Read(datafile& n, const std::string& sFileName, const char sListSep = ',')
{
// Open the file!
std::ifstream file(sFileName);
if (file.is_open())
{
// These variables are outside of the read loop, as we will
// need to refer to previous iteration values in certain conditions
std::string sPropName = "";
std::string sPropValue = "";
// The file is fundamentally structured as a stack, so we will read it
// in a such, but note the data structure in memory is not explicitly
// stored in a stack, but one is constructed implicitly via the nodes
// owning other nodes (aka a tree)
// I dont want to accidentally create copies all over the place, nor do
// I want to use pointer syntax, so being a bit different and stupidly
// using std::reference_wrapper, so I can store references to datafile
// nodes in a std::container.
std::stack<std::reference_wrapper<datafile>> stkPath;
stkPath.push(n);
// Read file line by line and process
while (!file.eof())
{
// Read line
std::string line;
std::getline(file, line);
// This little lambda removes whitespace from
// beginning and end of supplied string
auto trim = [](std::string& s)
{
s.erase(0, s.find_first_not_of(" \t\n\r\f\v"));
s.erase(s.find_last_not_of(" \t\n\r\f\v") + 1);
};
trim(line);
// If line has content
if (!line.empty())
{
// Test if its a comment...
if (line[0] == '#')
{
// ...it is a comment, so ignore
datafile comment;
comment.m_bIsComment = true;
stkPath.top().get().m_vecObjects.push_back({ line, comment });
}
else
{
// ...it is content, so parse. Firstly, find if the line
// contains an assignment. If it does then it's a property...
size_t x = line.find_first_of('=');
if (x != std::string::npos)
{
// ...so split up the property into a name, and its values!
// Extract the property name, which is all characters up to
// first assignment, trim any whitespace from ends
sPropName = line.substr(0, x);
trim(sPropName);
// Extract the property value, which is all characters after
// the first assignment operator, trim any whitespace from ends
sPropValue = line.substr(x + 1, line.size());
trim(sPropValue);
// The value may be in list form: a, b, c, d, e, f etc and some of those
// elements may exist in quotes a, b, c, "d, e", f. So we need to iterate
// character by character and break up the value
bool bInQuotes = false;
std::string sToken;
size_t nTokenCount = 0;
for (const auto c : sPropValue)
{
// Is character a quote...
if (c == '\"')
{
// ...yes, so toggle quote state
bInQuotes = !bInQuotes;
}
else
{
// ...no, so proceed creating token. If we are in quote state
// then just append characters until we exit quote state.
if (bInQuotes)
{
sToken.append(1, c);
}
else
{
// Is the character our seperator? If it is
if (c == sListSep)
{
// Clean up the token
trim(sToken);
// Add it to the vector of values for this property
stkPath.top().get()[sPropName].SetString(sToken, nTokenCount);
// Reset our token state
sToken.clear();
nTokenCount++;
}
else
{
// It isnt, so just append to token
sToken.append(1, c);
}
}
}
}
// Any residual characters at this point just make up the final token,
// so clean it up and add it to the vector of values
if (!sToken.empty())
{
trim(sToken);
stkPath.top().get()[sPropName].SetString(sToken, nTokenCount);
}
}
else
{
// ...but if it doesnt, then it's something structural
if (line[0] == '{')
{
// Open brace, so push this node to stack, subsequent properties
// will belong to the new node
stkPath.push(stkPath.top().get()[sPropName]);
}
else
{
if (line[0] == '}')
{
// Close brace, so this node has been defined, pop it from the
// stack
stkPath.pop();
}
else
{
// Line is a property with no assignment. Who knows whether this is useful,
// but we can simply add it as a valueless property...
sPropName = line;
// ...actually it is useful, as valuless properties are typically
// going to be the names of new datafile nodes on the next iteration
}
}
}
}
}
}
// Close and exit!
file.close();
return true;
}
// File not found, so fail
return false;
}
public:
inline datafile& operator[](const std::string& name)
{
// Check if this "node"'s map already contains an object with this name...
if (m_mapObjects.count(name) == 0)
{
// ...it did not! So create this object in the map. First get a vector id
// and link it with the name in the unordered_map
m_mapObjects[name] = m_vecObjects.size();
// then creating the new, blank object in the vector of objects
m_vecObjects.push_back({ name, datafile() });
}
// ...it exists! so return the object, by getting its index from the map, and using that
// index to look up a vector element.
return m_vecObjects[m_mapObjects[name]].second;
}
private:
// The "list of strings" that make up a property value
std::vector<std::string> m_vContent;
// Linkage to create "ordered" unordered_map. We have a vector of
// "properties", and the index to a specific element is mapped.
std::vector<std::pair<std::string, datafile>> m_vecObjects;
std::unordered_map<std::string, size_t> m_mapObjects;
protected:
// Used to identify if a property is a comment or not, not user facing
bool m_bIsComment = false;
};
}
Loading…
Cancel
Save