From c0d166c307c7b33ab0f37200e85ebf945bcd8f2c Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 10 Dec 2023 13:30:50 +0100 Subject: [PATCH] backend update from GZDoom. --- source/common/audio/music/i_music.cpp | 2 +- source/common/audio/music/i_soundfont.cpp | 12 +- source/common/audio/sound/oalsound.cpp | 2 +- source/common/audio/sound/s_soundinternal.h | 2 +- source/common/console/c_cvars.h | 3 + source/common/cutscenes/movieplayer.cpp | 5 +- source/common/engine/i_interface.h | 1 + source/common/engine/namedef.h | 5 + source/common/engine/sc_man.cpp | 2 +- source/common/engine/sc_man.h | 8 +- source/common/engine/serializer.cpp | 23 +- source/common/engine/serializer.h | 7 +- source/common/filesystem/include/fs_files.h | 111 ++++- .../common/filesystem/include/fs_filesystem.h | 1 - .../common/filesystem/include/resourcefile.h | 85 +++- source/common/filesystem/source/file_7z.cpp | 3 +- source/common/filesystem/source/file_grp.cpp | 4 +- source/common/filesystem/source/file_lump.cpp | 3 +- source/common/filesystem/source/file_pak.cpp | 4 +- source/common/filesystem/source/file_rff.cpp | 4 +- source/common/filesystem/source/file_ssi.cpp | 13 +- source/common/filesystem/source/file_wad.cpp | 15 +- .../common/filesystem/source/file_whres.cpp | 3 +- source/common/filesystem/source/file_zip.cpp | 36 +- source/common/filesystem/source/files.cpp | 82 ++-- .../common/filesystem/source/files_internal.h | 68 +++ .../common/filesystem/source/filesystem.cpp | 47 +- .../common/filesystem/source/resourcefile.cpp | 34 +- source/common/fonts/hexfont.cpp | 13 +- source/common/menu/savegamemanager.cpp | 25 +- source/common/models/model.cpp | 1 + source/common/models/model.h | 15 +- source/common/models/model_iqm.h | 9 +- source/common/models/models_iqm.cpp | 83 +++- source/common/objects/dobject.h | 2 - source/common/objects/dobjgc.h | 16 +- source/common/platform/posix/sdl/i_system.cpp | 9 +- source/common/platform/win32/i_system.cpp | 31 -- source/common/rendering/v_video.cpp | 3 +- source/common/scripting/backend/codegen.cpp | 403 ++++++++++++++++-- source/common/scripting/backend/codegen.h | 78 +++- source/common/scripting/backend/vmbuilder.cpp | 12 +- source/common/scripting/core/imports.cpp | 18 + source/common/scripting/core/types.cpp | 142 +++++- source/common/scripting/core/types.h | 1 + source/common/scripting/frontend/ast.cpp | 50 +++ .../common/scripting/frontend/zcc-parse.lemon | 50 +++ .../common/scripting/frontend/zcc_compile.cpp | 57 ++- .../common/scripting/frontend/zcc_compile.h | 2 +- .../common/scripting/frontend/zcc_parser.cpp | 40 ++ source/common/scripting/frontend/zcc_parser.h | 28 ++ source/common/scripting/vm/vm.h | 6 + source/common/scripting/vm/vmframe.cpp | 39 +- source/common/scripting/vm/vmintern.h | 2 + source/common/textures/formats/anmtexture.cpp | 3 +- source/common/textures/formats/pcxtexture.cpp | 8 +- .../common/textures/formats/webptexture.cpp | 4 +- source/common/textures/textureid.h | 3 + source/common/utility/tarray.h | 38 ++ source/core/codegen_raze.cpp | 16 + source/core/initfs.cpp | 21 +- source/core/maphack.cpp | 2 +- source/core/maploader.cpp | 6 +- source/core/menu/loadsavemenu.cpp | 6 +- source/core/palette.cpp | 2 +- source/core/raze_sound.cpp | 7 +- source/core/raze_sound.h | 2 +- source/core/savegamehelp.cpp | 18 +- source/core/searchpaths.cpp | 8 +- source/core/states.cpp | 2 +- source/core/states.h | 3 +- source/games/blood/src/db.cpp | 4 +- source/games/exhumed/src/movie.cpp | 2 +- source/games/sw/src/scrip2.cpp | 13 +- 74 files changed, 1496 insertions(+), 392 deletions(-) diff --git a/source/common/audio/music/i_music.cpp b/source/common/audio/music/i_music.cpp index 9f6165102..1f17cf884 100644 --- a/source/common/audio/music/i_music.cpp +++ b/source/common/audio/music/i_music.cpp @@ -337,7 +337,7 @@ static ZMusic_MidiSource GetMIDISource(const char *fn) } auto data = wlump.Read(); - auto source = ZMusic_CreateMIDISource(data.data(), data.size(), type); + auto source = ZMusic_CreateMIDISource(data.bytes(), data.size(), type); if (source == nullptr) { diff --git a/source/common/audio/music/i_soundfont.cpp b/source/common/audio/music/i_soundfont.cpp index e1059fc12..e4a6bc39f 100644 --- a/source/common/audio/music/i_soundfont.cpp +++ b/source/common/audio/music/i_soundfont.cpp @@ -215,10 +215,10 @@ FileReader FZipPatReader::OpenFile(const char *name) FileReader fr; if (resf != nullptr) { - auto lump = resf->FindLump(name); - if (lump != nullptr) + auto lump = resf->FindEntry(name); + if (lump >= 0) { - return lump->NewReader(); + return resf->GetEntryReader(lump); } } fr.OpenFile(name); @@ -367,10 +367,10 @@ void FSoundFontManager::ProcessOneFile(const char* fn) auto zip = FResourceFile::OpenResourceFile(fn, true); if (zip != nullptr) { - if (zip->LumpCount() > 1) // Anything with just one lump cannot possibly be a packed GUS patch set so skip it right away and simplify the lookup code + if (zip->EntryCount() > 1) // Anything with just one lump cannot possibly be a packed GUS patch set so skip it right away and simplify the lookup code { - auto zipl = zip->FindLump("timidity.cfg"); - if (zipl != nullptr) + auto zipl = zip->FindEntry("timidity.cfg"); + if (zipl >= 0) { // It seems like this is what we are looking for FSoundFontInfo sft = { fb, fbe, fn, SF_GUS }; diff --git a/source/common/audio/sound/oalsound.cpp b/source/common/audio/sound/oalsound.cpp index 96809e7be..511a89fbd 100644 --- a/source/common/audio/sound/oalsound.cpp +++ b/source/common/audio/sound/oalsound.cpp @@ -1141,7 +1141,7 @@ SoundHandle OpenALSoundRenderer::LoadSound(uint8_t *sfxdata, int length, int def return retval; } - std::vector data; + TArray data; unsigned total = 0; unsigned got; diff --git a/source/common/audio/sound/s_soundinternal.h b/source/common/audio/sound/s_soundinternal.h index 91aea8d1d..1d007faef 100644 --- a/source/common/audio/sound/s_soundinternal.h +++ b/source/common/audio/sound/s_soundinternal.h @@ -216,7 +216,7 @@ private: // Checks if a copy of this sound is already playing. bool CheckSingular(FSoundID sound_id); - virtual std::vector ReadSound(int lumpnum) = 0; + virtual TArray ReadSound(int lumpnum) = 0; protected: virtual bool CheckSoundLimit(sfxinfo_t* sfx, const FVector3& pos, int near_limit, float limit_range, int sourcetype, const void* actor, int channel, float attenuation); diff --git a/source/common/console/c_cvars.h b/source/common/console/c_cvars.h index c560bb165..e9fc87420 100644 --- a/source/common/console/c_cvars.h +++ b/source/common/console/c_cvars.h @@ -218,6 +218,9 @@ public: void* GetExtraDataPointer(); + int pnum = -1; + FName userinfoName; + protected: virtual void DoSet (UCVarValue value, ECVarType type) = 0; virtual void InstantiateZSCVar() diff --git a/source/common/cutscenes/movieplayer.cpp b/source/common/cutscenes/movieplayer.cpp index 917c11cbc..ef49346f5 100644 --- a/source/common/cutscenes/movieplayer.cpp +++ b/source/common/cutscenes/movieplayer.cpp @@ -153,7 +153,7 @@ class AnmPlayer : public MoviePlayer { // This doesn't need its own class type anim_t anim; - std::vector buffer; + FileSys::ResourceData buffer; int numframes = 0; int curframe = 1; int frametime = 0; @@ -171,9 +171,10 @@ public: memcpy(frameTicks, frameticks, 3 * sizeof(int)); flags = flags_; buffer = fr.ReadPadded(1); + if (buffer.size() < 4) return; fr.Close(); - if (ANIM_LoadAnim(&anim, buffer.data(), buffer.size() - 1) < 0) + if (ANIM_LoadAnim(&anim, buffer.bytes(), buffer.size() - 1) < 0) { return; } diff --git a/source/common/engine/i_interface.h b/source/common/engine/i_interface.h index 6679184de..ff35d6286 100644 --- a/source/common/engine/i_interface.h +++ b/source/common/engine/i_interface.h @@ -48,6 +48,7 @@ struct SystemCallbacks bool (*OkForLocalization)(FTextureID, const char*); FConfigFile* (*GetConfig)(); bool (*WantEscape)(); + FTranslationID(*RemapTranslation)(FTranslationID trans); }; extern SystemCallbacks sysCallbacks; diff --git a/source/common/engine/namedef.h b/source/common/engine/namedef.h index e76186f21..f857e9320 100644 --- a/source/common/engine/namedef.h +++ b/source/common/engine/namedef.h @@ -10,6 +10,7 @@ xx(Object) xx(Actor) xx(Class) xx(Thinker) +xx(VisualThinker) xx(Crosshairs) xx(Untranslated) @@ -134,6 +135,10 @@ xx(FVector3) xx(FVector4) xx(FQuat) xx(let) +xx(BlockThingsIterator) +xx(BlockLinesIterator) +xx(ActorIterator) +xx(ThinkerIterator) xx(Min) xx(Max) diff --git a/source/common/engine/sc_man.cpp b/source/common/engine/sc_man.cpp index cc72273a1..e8423178d 100644 --- a/source/common/engine/sc_man.cpp +++ b/source/common/engine/sc_man.cpp @@ -150,7 +150,7 @@ bool FScanner::OpenFile (const char *name) auto filebuff = fr.Read(); if (filebuff.size() == 0 && filesize > 0) return false; - ScriptBuffer = FString((const char *)filebuff.data(), filesize); + ScriptBuffer = FString(filebuff.string(), filesize); ScriptName = name; // This is used for error messages so the full file name is preferable LumpNum = -1; PrepareScript (); diff --git a/source/common/engine/sc_man.h b/source/common/engine/sc_man.h index 307831dba..32848a4a6 100644 --- a/source/common/engine/sc_man.h +++ b/source/common/engine/sc_man.h @@ -71,12 +71,10 @@ public: void Open(const char *lumpname); bool OpenFile(const char *filename); void OpenMem(const char *name, const char *buffer, int size); - void OpenMem(const char *name, const TArray &buffer) - { - OpenMem(name, (const char*)buffer.Data(), buffer.Size()); - } - void OpenMem(const char* name, const std::vector& buffer) + template + void OpenMem(const char* name, const T& buffer) { + static_assert(sizeof(typename T::value_type) == 1); OpenMem(name, (const char*)buffer.data(), (int)buffer.size()); } void OpenString(const char *name, FString buffer); diff --git a/source/common/engine/serializer.cpp b/source/common/engine/serializer.cpp index 71a0031b6..d7b94739b 100644 --- a/source/common/engine/serializer.cpp +++ b/source/common/engine/serializer.cpp @@ -56,6 +56,7 @@ #include "texturemanager.h" #include "base64.h" #include "vm.h" +#include "i_interface.h" using namespace FileSys; @@ -1207,7 +1208,14 @@ FSerializer& Serialize(FSerializer& arc, const char* key, FTranslationID& value, int v = value.index(); int* defv = (int*)defval; Serialize(arc, key, v, defv); - value = FTranslationID::fromInt(v); + + if (arc.isReading()) + { + // allow games to alter the loaded value to handle dynamic lists. + if (sysCallbacks.RemapTranslation) value = sysCallbacks.RemapTranslation(FTranslationID::fromInt(v)); + else value = FTranslationID::fromInt(v); + } + return arc; } @@ -1749,6 +1757,19 @@ void SerializeFunctionPointer(FSerializer &arc, const char *key, FunctionPointer } } +bool FSerializer::ReadOptionalInt(const char * key, int &into) +{ + if(!isReading()) return false; + + auto val = r->FindKey(key); + if(val && val->IsInt()) + { + into = val->GetInt(); + return true; + } + return false; +} + #include "renderstyle.h" FSerializer& Serialize(FSerializer& arc, const char* key, FRenderStyle& style, FRenderStyle* def) { diff --git a/source/common/engine/serializer.h b/source/common/engine/serializer.h index ec1d10949..29677237b 100644 --- a/source/common/engine/serializer.h +++ b/source/common/engine/serializer.h @@ -108,6 +108,10 @@ public: FSerializer &AddString(const char *key, const char *charptr); const char *GetString(const char *key); FSerializer &ScriptNum(const char *key, int &num); + + + bool ReadOptionalInt(const char * key, int &into); + bool isReading() const { return r != nullptr; @@ -240,7 +244,8 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FName &value, FName *d FSerializer &Serialize(FSerializer &arc, const char *key, FSoundID &sid, FSoundID *def); FSerializer &Serialize(FSerializer &arc, const char *key, FString &sid, FString *def); FSerializer &Serialize(FSerializer &arc, const char *key, NumericValue &sid, NumericValue *def); -FSerializer &Serialize(FSerializer &arc, const char *key, struct ModelOverride &sid, struct ModelOverride *def); +FSerializer &Serialize(FSerializer &arc, const char *key, struct ModelOverride &mo, struct ModelOverride *def); +FSerializer &Serialize(FSerializer &arc, const char *key, struct AnimOverride &ao, struct AnimOverride *def); FSerializer& Serialize(FSerializer& arc, const char* key, FTranslationID& value, FTranslationID* defval); void SerializeFunctionPointer(FSerializer &arc, const char *key, FunctionPointerValue *&p); diff --git a/source/common/filesystem/include/fs_files.h b/source/common/filesystem/include/fs_files.h index 756a15007..7a2871a71 100644 --- a/source/common/filesystem/include/fs_files.h +++ b/source/common/filesystem/include/fs_files.h @@ -4,7 +4,7 @@ ** **--------------------------------------------------------------------------- ** Copyright 1998-2008 Randy Heit -** Copyright 2005-2008 Christoph Oelckers +** Copyright 2005-2023 Christoph Oelckers ** All rights reserved. ** ** Redistribution and use in source and binary forms, with or without @@ -90,6 +90,84 @@ enum class FileReader; +// an opaque memory buffer to the file's content. Can either own the memory or just point to an external buffer. +class ResourceData +{ + void* memory; + size_t length; + bool owned; + +public: + using value_type = uint8_t; + ResourceData() { memory = nullptr; length = 0; owned = true; } + const void* data() const { return memory; } + size_t size() const { return length; } + const char* string() const { return (const char*)memory; } + const uint8_t* bytes() const { return (const uint8_t*)memory; } + + ResourceData& operator = (const ResourceData& copy) + { + if (owned && memory) free(memory); + length = copy.length; + owned = copy.owned; + if (owned) + { + memory = malloc(length); + memcpy(memory, copy.memory, length); + } + else memory = copy.memory; + return *this; + } + + ResourceData& operator = (ResourceData&& copy) noexcept + { + if (owned && memory) free(memory); + length = copy.length; + owned = copy.owned; + memory = copy.memory; + copy.memory = nullptr; + copy.length = 0; + copy.owned = true; + return *this; + } + + ResourceData(const ResourceData& copy) + { + memory = nullptr; + *this = copy; + } + + ~ResourceData() + { + if (owned && memory) free(memory); + } + + void* allocate(size_t len) + { + if (!owned) memory = nullptr; + length = len; + owned = true; + memory = realloc(memory, length); + return memory; + } + + void set(const void* mem, size_t len) + { + memory = (void*)mem; + length = len; + owned = false; + } + + void clear() + { + if (owned && memory) free(memory); + memory = nullptr; + length = 0; + owned = true; + } + +}; + class FileReaderInterface { public: @@ -171,10 +249,12 @@ public: mReader = nullptr; } - bool OpenFile(const char *filename, Size start = 0, Size length = -1); + bool OpenFile(const char *filename, Size start = 0, Size length = -1, bool buffered = false); bool OpenFilePart(FileReader &parent, Size start, Size length); bool OpenMemory(const void *mem, Size length); // read directly from the buffer bool OpenMemoryArray(const void *mem, Size length); // read from a copy of the buffer. + bool OpenMemoryArray(std::vector& data); // take the given array + bool OpenMemoryArray(ResourceData& data); // take the given array bool OpenMemoryArray(std::function&)> getter); // read contents to a buffer and return a reader to it bool OpenDecompressor(FileReader &parent, Size length, int method, bool seekable, bool exceptions = false); // creates a decompressor stream. 'seekable' uses a buffered version so that the Seek and Tell methods can be used. @@ -193,33 +273,34 @@ public: return mReader->Read(buffer, len); } - std::vector Read(size_t len) + ResourceData Read(size_t len) { - std::vector buffer(len); + ResourceData buffer; if (len > 0) { - Size length = mReader->Read(&buffer[0], len); - buffer.resize((size_t)length); + Size length = mReader->Read(buffer.allocate(len), len); + if ((size_t)length < len) buffer.allocate(length); } return buffer; } - std::vector Read() + ResourceData Read() { return Read(GetLength()); } - std::vector ReadPadded(size_t padding) + ResourceData ReadPadded(size_t padding) { auto len = GetLength(); - std::vector buffer(len + padding); + ResourceData buffer; + if (len > 0) { - Size length = mReader->Read(&buffer[0], len); + auto p = (char*)buffer.allocate(len + padding); + Size length = mReader->Read(p, len); if (length < len) buffer.clear(); - else memset(buffer.data() + len, 0, padding); + else memset(p + len, 0, padding); } - else buffer[0] = 0; return buffer; } @@ -353,13 +434,13 @@ protected: class BufferWriter : public FileWriter { protected: - TArray mBuffer; + std::vector mBuffer; public: BufferWriter() {} virtual size_t Write(const void *buffer, size_t len) override; - TArray *GetBuffer() { return &mBuffer; } - TArray&& TakeBuffer() { return std::move(mBuffer); } + std::vector *GetBuffer() { return &mBuffer; } + std::vector&& TakeBuffer() { return std::move(mBuffer); } }; } diff --git a/source/common/filesystem/include/fs_filesystem.h b/source/common/filesystem/include/fs_filesystem.h index bac46e1bb..89a20638b 100644 --- a/source/common/filesystem/include/fs_filesystem.h +++ b/source/common/filesystem/include/fs_filesystem.h @@ -174,7 +174,6 @@ public: int AddFromBuffer(const char* name, const char* type, char* data, int size, int id, int flags); FileReader* GetFileReader(int wadnum); // Gets a FileReader object to the entire WAD void InitHashChains(); - FResourceLump* GetFileAt(int no); protected: diff --git a/source/common/filesystem/include/resourcefile.h b/source/common/filesystem/include/resourcefile.h index f714c7995..e2787fd12 100644 --- a/source/common/filesystem/include/resourcefile.h +++ b/source/common/filesystem/include/resourcefile.h @@ -88,8 +88,8 @@ enum ELumpFlags // This holds a compresed Zip entry with all needed info to decompress it. struct FCompressedBuffer { - unsigned mSize; - unsigned mCompressedSize; + size_t mSize; + size_t mCompressedSize; int mMethod; int mZipFlags; unsigned mCRC32; @@ -110,18 +110,34 @@ struct FCompressedBuffer struct FResourceLump { +protected: friend class FResourceFile; friend class FWadFile; // this still needs direct access. + friend class FileData; + friend class FileSystem; + friend class FLumpFile; + friend class FLumpReader; + friend class FGrpFile; + friend class F7ZFile; + friend class FSSIFile; + friend class FWHResFile; + friend class FZipFile; + friend class FPakFile; + friend class FRFFFile; + friend class FDirectory; + friend int lumpcmp(const void* a, const void* b); + int LumpSize; int RefCount; -protected: +//protected: const char* FullName; -public: +//public: uint8_t Flags; char * Cache; FResourceFile * Owner; +public: FResourceLump() { Cache = NULL; @@ -129,9 +145,12 @@ public: Flags = 0; RefCount = 0; FullName = ""; + LumpSize = 0; } - virtual ~FResourceLump(); + +protected: + virtual FileReader *GetReader(); virtual FileReader NewReader(); virtual int GetFileOffset() { return -1; } @@ -157,9 +176,9 @@ protected: class FResourceFile { public: +protected: FileReader Reader; const char* FileName; -protected: uint32_t NumLumps; char Hash[48]; StringPool* stringpool; @@ -186,15 +205,61 @@ public: static FResourceFile *OpenDirectory(const char *filename, LumpFilterInfo* filter = nullptr, FileSystemMessageFunc Printf = nullptr, StringPool* sp = nullptr); virtual ~FResourceFile(); // If this FResourceFile represents a directory, the Reader object is not usable so don't return it. - FileReader *GetReader() { return Reader.isOpen()? &Reader : nullptr; } - uint32_t LumpCount() const { return NumLumps; } + FileReader *GetContainerReader() { return Reader.isOpen()? &Reader : nullptr; } + const char* GetFileName() const { return FileName; } uint32_t GetFirstEntry() const { return FirstLump; } void SetFirstLump(uint32_t f) { FirstLump = f; } const char* GetHash() const { return Hash; } - virtual FResourceLump *GetLump(int no) = 0; - FResourceLump *FindLump(const char *name); + + int EntryCount() const { return NumLumps; } + int FindEntry(const char* name); + + size_t Length(int entry) + { + auto l = GetLump(entry); + return l ? l->LumpSize : -1; + } + + FileReader GetEntryReader(int entry, bool newreader = true) + { + auto l = GetLump(entry); + return l ? l->NewReader() : FileReader(); + } + + int GetEntryFlags(int entry) + { + auto l = GetLump(entry); + return l ? l->Flags : 0; + } + + ResourceData Read(int entry) + { + auto fr = GetEntryReader(entry, false); + return fr.Read(); + } + + const char* getName(int entry) + { + auto l = GetLump(entry); + return l ? l->FullName : nullptr; + } + FCompressedBuffer GetRawData(int entry) + { + auto l = GetLump(entry); + if (!l) return {}; + return l->GetRawData(); + } + + FileReader Destroy() + { + auto fr = std::move(Reader); + delete this; + return fr; + } + + }; diff --git a/source/common/filesystem/source/file_7z.cpp b/source/common/filesystem/source/file_7z.cpp index 1be0d6a1c..0740ceca1 100644 --- a/source/common/filesystem/source/file_7z.cpp +++ b/source/common/filesystem/source/file_7z.cpp @@ -367,8 +367,7 @@ FResourceFile *Check7Z(const char *filename, FileReader &file, LumpFilterInfo* f auto rf = new F7ZFile(filename, file, sp); if (rf->Open(filter, Printf)) return rf; - file = std::move(rf->Reader); // to avoid destruction of reader - delete rf; + file = rf->Destroy(); } } return NULL; diff --git a/source/common/filesystem/source/file_grp.cpp b/source/common/filesystem/source/file_grp.cpp index b289b121d..05299f940 100644 --- a/source/common/filesystem/source/file_grp.cpp +++ b/source/common/filesystem/source/file_grp.cpp @@ -145,9 +145,7 @@ FResourceFile *CheckGRP(const char *filename, FileReader &file, LumpFilterInfo* { auto rf = new FGrpFile(filename, file, sp); if (rf->Open(filter)) return rf; - - file = std::move(rf->Reader); // to avoid destruction of reader - delete rf; + file = rf->Destroy(); } } return NULL; diff --git a/source/common/filesystem/source/file_lump.cpp b/source/common/filesystem/source/file_lump.cpp index ad4406a0f..94da2af4f 100644 --- a/source/common/filesystem/source/file_lump.cpp +++ b/source/common/filesystem/source/file_lump.cpp @@ -89,8 +89,7 @@ FResourceFile *CheckLump(const char *filename, FileReader &file, LumpFilterInfo* // always succeeds auto rf = new FLumpFile(filename, file, sp); if (rf->Open(filter)) return rf; - file = std::move(rf->Reader); // to avoid destruction of reader - delete rf; + file = rf->Destroy(); return NULL; } diff --git a/source/common/filesystem/source/file_pak.cpp b/source/common/filesystem/source/file_pak.cpp index 4e3b3ef93..12ab2f4e2 100644 --- a/source/common/filesystem/source/file_pak.cpp +++ b/source/common/filesystem/source/file_pak.cpp @@ -138,9 +138,7 @@ FResourceFile *CheckPak(const char *filename, FileReader &file, LumpFilterInfo* { auto rf = new FPakFile(filename, file, sp); if (rf->Open(filter)) return rf; - - file = std::move(rf->Reader); // to avoid destruction of reader - delete rf; + file = rf->Destroy(); } } return NULL; diff --git a/source/common/filesystem/source/file_rff.cpp b/source/common/filesystem/source/file_rff.cpp index 1d3cf15bf..dff7b69e9 100644 --- a/source/common/filesystem/source/file_rff.cpp +++ b/source/common/filesystem/source/file_rff.cpp @@ -252,9 +252,7 @@ FResourceFile *CheckRFF(const char *filename, FileReader &file, LumpFilterInfo* { auto rf = new FRFFFile(filename, file, sp); if (rf->Open(filter)) return rf; - - file = std::move(rf->Reader); // to avoid destruction of reader - delete rf; + file = rf->Destroy(); } } return NULL; diff --git a/source/common/filesystem/source/file_ssi.cpp b/source/common/filesystem/source/file_ssi.cpp index 4b68997f0..f23c8e5ea 100644 --- a/source/common/filesystem/source/file_ssi.cpp +++ b/source/common/filesystem/source/file_ssi.cpp @@ -46,7 +46,7 @@ class FSSIFile : public FUncompressedFile { public: FSSIFile(const char * filename, FileReader &file, StringPool* sp); - bool Open(int version, int lumpcount, LumpFilterInfo* filter); + bool Open(int version, int EntryCount, LumpFilterInfo* filter); }; @@ -68,13 +68,13 @@ FSSIFile::FSSIFile(const char *filename, FileReader &file, StringPool* sp) // //========================================================================== -bool FSSIFile::Open(int version, int lumpcount, LumpFilterInfo*) +bool FSSIFile::Open(int version, int EntryCount, LumpFilterInfo*) { - NumLumps = lumpcount*2; - Lumps.Resize(lumpcount*2); + NumLumps = EntryCount*2; + Lumps.Resize(EntryCount*2); - int32_t j = (version == 2 ? 267 : 254) + (lumpcount * 121); + int32_t j = (version == 2 ? 267 : 254) + (EntryCount * 121); for (uint32_t i = 0; i < NumLumps; i+=2) { char fn[13]; @@ -147,8 +147,7 @@ FResourceFile* CheckSSI(const char* filename, FileReader& file, LumpFilterInfo* } auto ssi = new FSSIFile(filename, file, sp); if (ssi->Open(version, numfiles, filter)) return ssi; - file = std::move(ssi->Reader); // to avoid destruction of reader - delete ssi; + file = ssi->Destroy(); } } return nullptr; diff --git a/source/common/filesystem/source/file_wad.cpp b/source/common/filesystem/source/file_wad.cpp index 13eb0b098..3451b7da8 100644 --- a/source/common/filesystem/source/file_wad.cpp +++ b/source/common/filesystem/source/file_wad.cpp @@ -76,8 +76,8 @@ public: { if(!Compressed) { - Owner->Reader.Seek(Position, FileReader::SeekSet); - return &Owner->Reader; + Owner->GetContainerReader()->Seek(Position, FileReader::SeekSet); + return Owner->GetContainerReader(); } return NULL; } @@ -85,7 +85,7 @@ public: { if(!Compressed) { - const char * buffer = Owner->Reader.GetBuffer(); + const char * buffer = Owner->GetContainerReader()->GetBuffer(); if (buffer != NULL) { @@ -96,20 +96,20 @@ public: } } - Owner->Reader.Seek(Position, FileReader::SeekSet); + Owner->GetContainerReader()->Seek(Position, FileReader::SeekSet); Cache = new char[LumpSize]; if(Compressed) { FileReader lzss; - if (lzss.OpenDecompressor(Owner->Reader, LumpSize, METHOD_LZSS, false, true)) + if (lzss.OpenDecompressor(*Owner->GetContainerReader(), LumpSize, METHOD_LZSS, false, true)) { lzss.Read(Cache, LumpSize); } } else { - auto read = Owner->Reader.Read(Cache, LumpSize); + auto read = Owner->GetContainerReader()->Read(Cache, LumpSize); if (read != LumpSize) { throw FileSystemException("only read %d of %d bytes", (int)read, (int)LumpSize); @@ -478,8 +478,7 @@ FResourceFile *CheckWad(const char *filename, FileReader &file, LumpFilterInfo* auto rf = new FWadFile(filename, file, sp); if (rf->Open(filter, Printf)) return rf; - file = std::move(rf->Reader); // to avoid destruction of reader - delete rf; + file = rf->Destroy(); } } return NULL; diff --git a/source/common/filesystem/source/file_whres.cpp b/source/common/filesystem/source/file_whres.cpp index cef800a0f..ffa8dd8a5 100644 --- a/source/common/filesystem/source/file_whres.cpp +++ b/source/common/filesystem/source/file_whres.cpp @@ -136,8 +136,7 @@ FResourceFile *CheckWHRes(const char *filename, FileReader &file, LumpFilterInfo } auto rf = new FWHResFile(filename, file, sp); if (rf->Open(filter)) return rf; - file = std::move(rf->Reader); // to avoid destruction of reader - delete rf; + file = rf->Destroy(); } return NULL; } diff --git a/source/common/filesystem/source/file_zip.cpp b/source/common/filesystem/source/file_zip.cpp index 155cbf45a..dfeb41ea8 100644 --- a/source/common/filesystem/source/file_zip.cpp +++ b/source/common/filesystem/source/file_zip.cpp @@ -52,7 +52,7 @@ namespace FileSys { // //========================================================================== -static bool UncompressZipLump(char *Cache, FileReader &Reader, int Method, int LumpSize, int CompressedSize, int GPFlags, bool exceptions) +static bool UncompressZipLump(char *Cache, FileReader &Reader, int Method, ptrdiff_t LumpSize, ptrdiff_t CompressedSize, int GPFlags, bool exceptions) { switch (Method) { @@ -79,7 +79,7 @@ static bool UncompressZipLump(char *Cache, FileReader &Reader, int Method, int L case METHOD_IMPLODE: { FZipExploder exploder; - if (exploder.Explode((unsigned char*)Cache, LumpSize, Reader, CompressedSize, GPFlags) == -1) + if (exploder.Explode((unsigned char*)Cache, (unsigned)LumpSize, Reader, (unsigned)CompressedSize, GPFlags) == -1) { // decompression failed so zero the cache. memset(Cache, 0, LumpSize); @@ -89,7 +89,7 @@ static bool UncompressZipLump(char *Cache, FileReader &Reader, int Method, int L case METHOD_SHRINK: { - ShrinkLoop((unsigned char *)Cache, LumpSize, Reader, CompressedSize); + ShrinkLoop((unsigned char *)Cache, (unsigned)LumpSize, Reader, (unsigned)CompressedSize); break; } @@ -445,8 +445,8 @@ FCompressedBuffer FZipLump::GetRawData() { FCompressedBuffer cbuf = { (unsigned)LumpSize, (unsigned)CompressedSize, Method, GPFlags, CRC32, new char[CompressedSize] }; if (NeedFileStart) SetLumpAddress(); - Owner->Reader.Seek(Position, FileReader::SeekSet); - Owner->Reader.Read(cbuf.mBuffer, CompressedSize); + Owner->GetContainerReader()->Seek(Position, FileReader::SeekSet); + Owner->GetContainerReader()->Read(cbuf.mBuffer, CompressedSize); return cbuf; } @@ -464,8 +464,8 @@ void FZipLump::SetLumpAddress() FZipLocalFileHeader localHeader; int skiplen; - Owner->Reader.Seek(Position, FileReader::SeekSet); - Owner->Reader.Read(&localHeader, sizeof(localHeader)); + Owner->GetContainerReader()->Seek(Position, FileReader::SeekSet); + Owner->GetContainerReader()->Read(&localHeader, sizeof(localHeader)); skiplen = LittleShort(localHeader.NameLength) + LittleShort(localHeader.ExtraLength); Position += sizeof(localHeader) + skiplen; NeedFileStart = false; @@ -484,8 +484,8 @@ FileReader *FZipLump::GetReader() if (Method == METHOD_STORED) { if (NeedFileStart) SetLumpAddress(); - Owner->Reader.Seek(Position, FileReader::SeekSet); - return &Owner->Reader; + Owner->GetContainerReader()->Seek(Position, FileReader::SeekSet); + return Owner->GetContainerReader(); } else return NULL; } @@ -501,7 +501,7 @@ int FZipLump::FillCache() if (NeedFileStart) SetLumpAddress(); const char *buffer; - if (Method == METHOD_STORED && (buffer = Owner->Reader.GetBuffer()) != NULL) + if (Method == METHOD_STORED && (buffer = Owner->GetContainerReader()->GetBuffer()) != NULL) { // This is an in-memory file so the cache can point directly to the file's data. Cache = const_cast(buffer) + Position; @@ -509,9 +509,9 @@ int FZipLump::FillCache() return -1; } - Owner->Reader.Seek(Position, FileReader::SeekSet); + Owner->GetContainerReader()->Seek(Position, FileReader::SeekSet); Cache = new char[LumpSize]; - UncompressZipLump(Cache, Owner->Reader, Method, LumpSize, CompressedSize, GPFlags, true); + UncompressZipLump(Cache, *Owner->GetContainerReader(), Method, LumpSize, CompressedSize, GPFlags, true); RefCount = 1; return 1; } @@ -548,9 +548,7 @@ FResourceFile *CheckZip(const char *filename, FileReader &file, LumpFilterInfo* { auto rf = new FZipFile(filename, file, sp); if (rf->Open(filter, Printf)) return rf; - - file = std::move(rf->Reader); // to avoid destruction of reader - delete rf; + file = rf->Destroy(); } } return NULL; @@ -606,8 +604,8 @@ static int AppendToZip(FileWriter *zip_file, const FCompressedBuffer &content, s local.ModDate = LittleShort(dostime.first); local.ModTime = LittleShort(dostime.second); local.CRC32 = content.mCRC32; - local.UncompressedSize = LittleLong(content.mSize); - local.CompressedSize = LittleLong(content.mCompressedSize); + local.UncompressedSize = LittleLong((unsigned)content.mSize); + local.CompressedSize = LittleLong((unsigned)content.mCompressedSize); local.NameLength = LittleShort((unsigned short)strlen(content.filename)); local.ExtraLength = 0; @@ -648,8 +646,8 @@ int AppendCentralDirectory(FileWriter *zip_file, const FCompressedBuffer &conten dir.ModTime = LittleShort(dostime.first); dir.ModDate = LittleShort(dostime.second); dir.CRC32 = content.mCRC32; - dir.CompressedSize32 = LittleLong(content.mCompressedSize); - dir.UncompressedSize32 = LittleLong(content.mSize); + dir.CompressedSize32 = LittleLong((unsigned)content.mCompressedSize); + dir.UncompressedSize32 = LittleLong((unsigned)content.mSize); dir.NameLength = LittleShort((unsigned short)strlen(content.filename)); dir.ExtraLength = 0; dir.CommentLength = 0; diff --git a/source/common/filesystem/source/files.cpp b/source/common/filesystem/source/files.cpp index 271831e36..7bf013060 100644 --- a/source/common/filesystem/source/files.cpp +++ b/source/common/filesystem/source/files.cpp @@ -34,6 +34,7 @@ */ #include +#include #include "files_internal.h" namespace FileSys { @@ -285,7 +286,7 @@ ptrdiff_t MemoryReader::Seek(ptrdiff_t offset, int origin) ptrdiff_t MemoryReader::Read(void *buffer, ptrdiff_t len) { - if (len>Length - FilePos) len = Length - FilePos; + if (len > Length - FilePos) len = Length - FilePos; if (len<0) len = 0; memcpy(buffer, bufptr + FilePos, len); FilePos += len; @@ -322,40 +323,37 @@ char *MemoryReader::Gets(char *strbuf, ptrdiff_t len) return strbuf; } -//========================================================================== -// -// MemoryArrayReader -// -// reads data from an array of memory -// -//========================================================================== - -class MemoryArrayReader : public MemoryReader +int BufferingReader::FillBuffer(ptrdiff_t newpos) { - std::vector buf; - -public: - MemoryArrayReader(const char *buffer, ptrdiff_t length) + if (newpos > Length) newpos = Length; + if (newpos < bufferpos) return 0; + auto read = baseReader->Read(&buf[bufferpos], newpos - bufferpos); + bufferpos += read; + if (bufferpos == Length) { - if (length > 0) - { - buf.resize(length); - memcpy(&buf[0], buffer, length); - } - UpdateBuffer(); + // we have read the entire file, so delete our data provider. + baseReader.reset(); } + return read == newpos - bufferpos ? 0 : -1; +} - std::vector &GetArray() { return buf; } - - void UpdateBuffer() - { - bufptr = (const char*)buf.data(); - FilePos = 0; - Length = buf.size(); - } -}; +ptrdiff_t BufferingReader::Seek(ptrdiff_t offset, int origin) +{ + if (-1 == MemoryReader::Seek(offset, origin)) return -1; + return FillBuffer(FilePos); +} +ptrdiff_t BufferingReader::Read(void* buffer, ptrdiff_t len) +{ + if (FillBuffer(FilePos + len) < 0) return 0; + return MemoryReader::Read(buffer, len); +} +char* BufferingReader::Gets(char* strbuf, ptrdiff_t len) +{ + if (FillBuffer(FilePos + len) < 0) return nullptr; + return MemoryReader::Gets(strbuf, len); +} //========================================================================== // @@ -365,7 +363,7 @@ public: // //========================================================================== -bool FileReader::OpenFile(const char *filename, FileReader::Size start, FileReader::Size length) +bool FileReader::OpenFile(const char *filename, FileReader::Size start, FileReader::Size length, bool buffered) { auto reader = new StdFileReader; if (!reader->Open(filename, start, length)) @@ -374,7 +372,8 @@ bool FileReader::OpenFile(const char *filename, FileReader::Size start, FileRead return false; } Close(); - mReader = reader; + if (buffered) mReader = new BufferingReader(reader); + else mReader = reader; return true; } @@ -396,13 +395,27 @@ bool FileReader::OpenMemory(const void *mem, FileReader::Size length) bool FileReader::OpenMemoryArray(const void *mem, FileReader::Size length) { Close(); - mReader = new MemoryArrayReader((const char *)mem, length); + mReader = new MemoryArrayReader>((const char *)mem, length); + return true; +} + +bool FileReader::OpenMemoryArray(std::vector& data) +{ + Close(); + if (data.size() > 0) mReader = new MemoryArrayReader>(data); + return true; +} + +bool FileReader::OpenMemoryArray(ResourceData& data) +{ + Close(); + if (data.size() > 0) mReader = new MemoryArrayReader(data); return true; } bool FileReader::OpenMemoryArray(std::function&)> getter) { - auto reader = new MemoryArrayReader(nullptr, 0); + auto reader = new MemoryArrayReader>(nullptr, 0); if (getter(reader->GetArray())) { Close(); @@ -494,7 +507,8 @@ size_t FileWriter::Printf(const char *fmt, ...) size_t BufferWriter::Write(const void *buffer, size_t len) { - unsigned int ofs = mBuffer.Reserve((unsigned)len); + size_t ofs = mBuffer.size(); + mBuffer.resize(ofs + len); memcpy(&mBuffer[ofs], buffer, len); return len; } diff --git a/source/common/filesystem/source/files_internal.h b/source/common/filesystem/source/files_internal.h index 3317796ac..aa3595cbf 100644 --- a/source/common/filesystem/source/files_internal.h +++ b/source/common/filesystem/source/files_internal.h @@ -1,5 +1,6 @@ #pragma once +#include #include "fs_files.h" namespace FileSys { @@ -28,4 +29,71 @@ public: virtual const char *GetBuffer() const override { return bufptr; } }; +class BufferingReader : public MemoryReader +{ + std::vector buf; + std::unique_ptr baseReader; + ptrdiff_t bufferpos = 0; + + int FillBuffer(ptrdiff_t newpos); +public: + BufferingReader(FileReaderInterface* base) + : baseReader(base) + { + } + + ptrdiff_t Seek(ptrdiff_t offset, int origin) override; + ptrdiff_t Read(void* buffer, ptrdiff_t len) override; + char* Gets(char* strbuf, ptrdiff_t len) override; +}; + +//========================================================================== +// +// MemoryArrayReader +// +// reads data from an array of memory +// +//========================================================================== + +template +class MemoryArrayReader : public MemoryReader +{ + T buf; + +public: + MemoryArrayReader() + { + FilePos = 0; + Length = 0; + } + + MemoryArrayReader(const char* buffer, ptrdiff_t length) + { + if (length > 0) + { + buf.resize(length); + memcpy(&buf[0], buffer, length); + } + UpdateBuffer(); + } + + MemoryArrayReader(T& buffer) + { + buf = std::move(buffer); + UpdateBuffer(); + } + + std::vector& GetArray() { return buf; } + + void UpdateBuffer() + { + bufptr = (const char*)buf.data(); + FilePos = 0; + Length = buf.size(); + } +}; + +bool OpenMemoryArray(std::vector& data); // take the given array + + } diff --git a/source/common/filesystem/source/filesystem.cpp b/source/common/filesystem/source/filesystem.cpp index 0841ea68e..e265f5cba 100644 --- a/source/common/filesystem/source/filesystem.cpp +++ b/source/common/filesystem/source/filesystem.cpp @@ -404,14 +404,14 @@ void FileSystem::AddFile (const char *filename, FileReader *filer, LumpFilterInf if (resfile != NULL) { if (Printf) - Printf(FSMessageLevel::Message, "adding %s, %d lumps\n", filename, resfile->LumpCount()); + Printf(FSMessageLevel::Message, "adding %s, %d lumps\n", filename, resfile->EntryCount()); uint32_t lumpstart = (uint32_t)FileInfo.size(); resfile->SetFirstLump(lumpstart); - for (uint32_t i=0; i < resfile->LumpCount(); i++) + for (int i = 0; i < resfile->EntryCount(); i++) { - FResourceLump *lump = resfile->GetLump(i); + FResourceLump* lump = resfile->GetLump(i); FileInfo.resize(FileInfo.size() + 1); FileSystem::LumpRecord* lump_p = &FileInfo.back(); lump_p->SetFromLump((int)Files.size(), lump, stringpool); @@ -419,15 +419,15 @@ void FileSystem::AddFile (const char *filename, FileReader *filer, LumpFilterInf Files.push_back(resfile); - for (uint32_t i=0; i < resfile->LumpCount(); i++) + for (int i = 0; i < resfile->EntryCount(); i++) { - FResourceLump *lump = resfile->GetLump(i); - if (lump->Flags & LUMPF_EMBEDDED) + int flags = resfile->GetEntryFlags(i); + if (flags & LUMPF_EMBEDDED) { std::string path = filename; path += ':'; - path += lump->getName(); - auto embedded = lump->NewReader(); + path += resfile->getName(i); + auto embedded = resfile->GetEntryReader(i, true); AddFile(path.c_str(), &embedded, filter, Printf, hashfile); } } @@ -454,13 +454,12 @@ void FileSystem::AddFile (const char *filename, FileReader *filer, LumpFilterInf else fprintf(hashfile, "file: %s, Directory structure\n", filename); - for (uint32_t i = 0; i < resfile->LumpCount(); i++) + for (int i = 0; i < resfile->EntryCount(); i++) { - FResourceLump *lump = resfile->GetLump(i); - - if (!(lump->Flags & LUMPF_EMBEDDED)) + int flags = resfile->GetEntryFlags(i); + if (!(flags & LUMPF_EMBEDDED)) { - auto reader = lump->NewReader(); + auto reader = resfile->GetEntryReader(i, true); md5Hash(filereader, cksum); for (size_t j = 0; j < sizeof(cksum); ++j) @@ -468,7 +467,7 @@ void FileSystem::AddFile (const char *filename, FileReader *filer, LumpFilterInf snprintf(cksumout + (j * 2), 3, "%02X", cksum[j]); } - fprintf(hashfile, "file: %s, lump: %s, hash: %s, size: %d\n", filename, lump->getName(), cksumout, lump->LumpSize); + fprintf(hashfile, "file: %s, lump: %s, hash: %s, size: %llu\n", filename, resfile->getName(i), cksumout, (uint64_t)resfile->Length(i)); } } } @@ -1421,7 +1420,7 @@ FileReader *FileSystem::GetFileReader(int rfnum) return NULL; } - return Files[rfnum]->GetReader(); + return Files[rfnum]->GetContainerReader(); } //========================================================================== @@ -1441,7 +1440,7 @@ const char *FileSystem::GetResourceFileName (int rfnum) const noexcept return NULL; } - name = Files[rfnum]->FileName; + name = Files[rfnum]->GetFileName(); slash = strrchr (name, '/'); return (slash != nullptr && slash[1] != 0) ? slash+1 : name; } @@ -1473,7 +1472,7 @@ int FileSystem::GetLastEntry (int rfnum) const noexcept return 0; } - return Files[rfnum]->GetFirstEntry() + Files[rfnum]->LumpCount() - 1; + return Files[rfnum]->GetFirstEntry() + Files[rfnum]->EntryCount() - 1; } //========================================================================== @@ -1488,7 +1487,7 @@ int FileSystem::GetEntryCount (int rfnum) const noexcept return 0; } - return Files[rfnum]->LumpCount(); + return Files[rfnum]->EntryCount(); } @@ -1507,7 +1506,7 @@ const char *FileSystem::GetResourceFileFullName (int rfnum) const noexcept return nullptr; } - return Files[rfnum]->FileName; + return Files[rfnum]->GetFileName(); } @@ -1592,15 +1591,5 @@ static void PrintLastError (FileSystemMessageFunc Printf) } #endif -//========================================================================== -// -// NBlood style lookup functions -// -//========================================================================== - -FResourceLump* FileSystem::GetFileAt(int no) -{ - return FileInfo[no].lump; -} } diff --git a/source/common/filesystem/source/resourcefile.cpp b/source/common/filesystem/source/resourcefile.cpp index 64c620c3b..420755a1a 100644 --- a/source/common/filesystem/source/resourcefile.cpp +++ b/source/common/filesystem/source/resourcefile.cpp @@ -157,7 +157,7 @@ static bool IsWadInFolder(const FResourceFile* const archive, const char* const return false; } - const auto dirName = ExtractBaseName(archive->FileName); + const auto dirName = ExtractBaseName(archive->GetFileName()); const auto fileName = ExtractBaseName(resPath, true); const std::string filePath = dirName + '/' + fileName; @@ -242,7 +242,7 @@ void *FResourceLump::Lock() catch (const FileSystemException& err) { // enrich the message with info about this lump. - throw FileSystemException("%s, file '%s': %s", getName(), Owner->FileName, err.what()); + throw FileSystemException("%s, file '%s': %s", getName(), Owner->GetFileName(), err.what()); } } return Cache; @@ -360,13 +360,13 @@ int lumpcmp(const void * a, const void * b) // // Generates a hash identifier for use in file identification. // Potential uses are mod-wide compatibility settings or localization add-ons. -// This only hashes the lump directory but not the actual content +// This only hashes the directory but not the actual content // //========================================================================== void FResourceFile::GenerateHash() { - // hash the lump directory after sorting + // hash the directory after sorting using namespace FileSys::md5; auto n = snprintf(Hash, 48, "%08X-%04X-", (unsigned)Reader.GetLength(), NumLumps); @@ -377,9 +377,10 @@ void FResourceFile::GenerateHash() uint8_t digest[16]; for(uint32_t i = 0; i < NumLumps; i++) { - auto lump = GetLump(i); - md5_append(&state, (const uint8_t*)lump->FullName, (unsigned)strlen(lump->FullName) + 1); - md5_append(&state, (const uint8_t*)&lump->LumpSize, 4); + auto name = getName(i); + auto size = Length(i); + md5_append(&state, (const uint8_t*)name, (unsigned)strlen(name) + 1); + md5_append(&state, (const uint8_t*)&size, sizeof(size)); } md5_finish(&state, digest); for (auto c : digest) @@ -618,17 +619,16 @@ bool FResourceFile::FindPrefixRange(const char* filter, void *lumps, size_t lump // //========================================================================== -FResourceLump *FResourceFile::FindLump(const char *name) +int FResourceFile::FindEntry(const char *name) { for (unsigned i = 0; i < NumLumps; i++) { - FResourceLump *lump = GetLump(i); - if (!stricmp(name, lump->FullName)) + if (!stricmp(name, getName(i))) { - return lump; + return i; } } - return nullptr; + return -1; } //========================================================================== @@ -639,8 +639,8 @@ FResourceLump *FResourceFile::FindLump(const char *name) FileReader *FUncompressedLump::GetReader() { - Owner->Reader.Seek(Position, FileReader::SeekSet); - return &Owner->Reader; + Owner->GetContainerReader()->Seek(Position, FileReader::SeekSet); + return Owner->GetContainerReader(); } //========================================================================== @@ -651,7 +651,7 @@ FileReader *FUncompressedLump::GetReader() int FUncompressedLump::FillCache() { - const char * buffer = Owner->Reader.GetBuffer(); + const char * buffer = Owner->GetContainerReader()->GetBuffer(); if (buffer != NULL) { @@ -661,10 +661,10 @@ int FUncompressedLump::FillCache() return -1; } - Owner->Reader.Seek(Position, FileReader::SeekSet); + Owner->GetContainerReader()->Seek(Position, FileReader::SeekSet); Cache = new char[LumpSize]; - auto read = Owner->Reader.Read(Cache, LumpSize); + auto read = Owner->GetContainerReader()->Read(Cache, LumpSize); if (read != LumpSize) { throw FileSystemException("only read %d of %d bytes", (int)read, (int)LumpSize); diff --git a/source/common/fonts/hexfont.cpp b/source/common/fonts/hexfont.cpp index 95b7999bf..6a788c001 100644 --- a/source/common/fonts/hexfont.cpp +++ b/source/common/fonts/hexfont.cpp @@ -58,12 +58,12 @@ struct HexDataSource // //========================================================================== - void ParseDefinition(FileSys::FResourceLump* font) + void ParseDefinition(FResourceFile* resf, int index) { FScanner sc; - auto data = font->Lock(); - sc.OpenMem("newconsolefont.hex", (const char*)data, font->Size()); + auto data = resf->Read(index); + sc.OpenMem("newconsolefont.hex", data.string(), data.size()); sc.SetCMode(true); glyphdata.Push(0); // ensure that index 0 can be used as 'not present'. while (sc.GetString()) @@ -97,7 +97,6 @@ struct HexDataSource lumb = i * 255 / 17; SmallPal[i] = PalEntry(255, lumb, lumb, lumb); } - font->Unlock(); } }; @@ -440,8 +439,8 @@ void LoadHexFont(const char* filename) { auto resf = FResourceFile::OpenResourceFile(filename); if (resf == nullptr) I_FatalError("Unable to open %s", filename); - auto hexfont = resf->FindLump("newconsolefont.hex"); - if (hexfont == nullptr) I_FatalError("Unable to find newconsolefont.hex in %s", filename); - hexdata.ParseDefinition(hexfont); + auto hexfont = resf->FindEntry("newconsolefont.hex"); + if (hexfont < 0) I_FatalError("Unable to find newconsolefont.hex in %s", filename); + hexdata.ParseDefinition(resf, hexfont); delete resf; } diff --git a/source/common/menu/savegamemanager.cpp b/source/common/menu/savegamemanager.cpp index 35cf6674d..4682be7f2 100644 --- a/source/common/menu/savegamemanager.cpp +++ b/source/common/menu/savegamemanager.cpp @@ -297,37 +297,26 @@ unsigned FSavegameManagerBase::ExtractSaveData(int index) !node->bOldVersion && (resf = FResourceFile::OpenResourceFile(node->Filename.GetChars(), true)) != nullptr) { - auto info = resf->FindLump("info.json"); - if (info == nullptr) + auto info = resf->FindEntry("info.json"); + if (info < 0) { // this should not happen because the file has already been verified. return index; } - void* data = info->Lock(); + auto data = resf->Read(info); FSerializer arc; - if (!arc.OpenReader((const char*)data, info->LumpSize)) + if (!arc.OpenReader(data.string(), data.size())) { - info->Unlock(); return index; } - info->Unlock(); SaveCommentString = ExtractSaveComment(arc); - auto pic = resf->FindLump("savepic.png"); - if (pic != nullptr) + auto pic = resf->FindEntry("savepic.png"); + if (pic >= 0) { - FileReader picreader; - - picreader.OpenMemoryArray([=](std::vector &array) - { - auto cache = pic->Lock(); - array.resize(pic->LumpSize); - memcpy(&array[0], cache, pic->LumpSize); - pic->Unlock(); - return true; - }); + FileReader picreader = resf->GetEntryReader(pic); PNGHandle *png = M_VerifyPNG(picreader); if (png != nullptr) { diff --git a/source/common/models/model.cpp b/source/common/models/model.cpp index 2df92a370..4b9ab0b00 100644 --- a/source/common/models/model.cpp +++ b/source/common/models/model.cpp @@ -47,6 +47,7 @@ TArray savedModelFiles; TDeletingArray Models; TArray SpriteModelFrames; +TMap BaseSpriteModelFrames; ///////////////////////////////////////////////////////////////////////////// diff --git a/source/common/models/model.h b/source/common/models/model.h index 69b947ae1..84adab556 100644 --- a/source/common/models/model.h +++ b/source/common/models/model.h @@ -6,6 +6,8 @@ #include "matrix.h" #include "palettecontainer.h" #include "TRS.h" +#include "tarray.h" +#include "name.h" class DBoneComponents; class FModelRenderer; @@ -19,6 +21,7 @@ void FlushModels(); extern TArray savedModelFiles; extern TDeletingArray Models; extern TArray SpriteModelFrames; +extern TMap BaseSpriteModelFrames; #define MD3_MAX_SURFACES 32 #define MIN_MODELS 4 @@ -72,13 +75,20 @@ public: virtual ~FModel(); virtual bool Load(const char * fn, int lumpnum, const char * buffer, int length) = 0; + virtual int FindFrame(const char * name, bool nodefault = false) = 0; + + // [RL0] these are used for decoupled iqm animations + virtual int FindFirstFrame(FName name) { return FErr_NotFound; } + virtual int FindLastFrame(FName name) { return FErr_NotFound; } + virtual double FindFramerate(FName name) { return FErr_NotFound; } + virtual void RenderFrame(FModelRenderer *renderer, FGameTexture * skin, int frame, int frame2, double inter, FTranslationID translation, const FTextureID* surfaceskinids, const TArray& boneData, int boneStartPosition) = 0; virtual void BuildVertexBuffer(FModelRenderer *renderer) = 0; virtual void AddSkins(uint8_t *hitlist, const FTextureID* surfaceskinids) = 0; virtual float getAspectFactor(float vscale) { return 1.f; } virtual const TArray* AttachAnimationData() { return nullptr; }; - virtual const TArray CalculateBones(int frame1, int frame2, double inter, const TArray* animationData, DBoneComponents* bones, int index) { return {}; }; + virtual const TArray CalculateBones(int frame1, int frame2, float inter, int frame1_prev, float inter1_prev, int frame2_prev, float inter2_prev, const TArray* animationData, DBoneComponents* bones, int index) { return {}; }; void SetVertexBuffer(int type, IModelVertexBuffer *buffer) { mVBuf[type] = buffer; } IModelVertexBuffer *GetVertexBuffer(int type) const { return mVBuf[type]; } @@ -86,7 +96,8 @@ public: bool hasSurfaces = false; FString mFileName; - + + FSpriteModelFrame *baseFrame; private: IModelVertexBuffer *mVBuf[NumModelRendererTypes]; }; diff --git a/source/common/models/model_iqm.h b/source/common/models/model_iqm.h index 701c1e793..464f5c13a 100644 --- a/source/common/models/model_iqm.h +++ b/source/common/models/model_iqm.h @@ -6,6 +6,7 @@ #include "matrix.h" #include "common/rendering/i_modelvertexbuffer.h" #include "m_swap.h" +#include "name.h" class DBoneComponents; @@ -112,11 +113,14 @@ public: bool Load(const char* fn, int lumpnum, const char* buffer, int length) override; int FindFrame(const char* name, bool nodefault) override; + int FindFirstFrame(FName name) override; + int FindLastFrame(FName name) override; + double FindFramerate(FName name) override; void RenderFrame(FModelRenderer* renderer, FGameTexture* skin, int frame, int frame2, double inter, FTranslationID translation, const FTextureID* surfaceskinids, const TArray& boneData, int boneStartPosition) override; void BuildVertexBuffer(FModelRenderer* renderer) override; void AddSkins(uint8_t* hitlist, const FTextureID* surfaceskinids) override; const TArray* AttachAnimationData() override; - const TArray CalculateBones(int frame1, int frame2, double inter, const TArray* animationData, DBoneComponents* bones, int index) override; + const TArray CalculateBones(int frame1, int frame2, float inter, int frame1_prev, float inter1_prev, int frame2_prev, float inter2_prev, const TArray* animationData, DBoneComponents* bones, int index) override; private: void LoadGeometry(); @@ -129,6 +133,9 @@ private: void LoadBlendWeights(IQMFileReader& reader, const IQMVertexArray& vertexArray); int mLumpNum = -1; + + TMap NamedAnimations; + TArray Meshes; TArray Triangles; TArray Adjacency; diff --git a/source/common/models/models_iqm.cpp b/source/common/models/models_iqm.cpp index df65a61d6..429da9b14 100644 --- a/source/common/models/models_iqm.cpp +++ b/source/common/models/models_iqm.cpp @@ -137,9 +137,12 @@ bool IQMModel::Load(const char* path, int lumpnum, const char* buffer, int lengt } reader.SeekTo(ofs_anims); - for (IQMAnim& anim : Anims) + for(int i = 0; i < Anims.Size(); i++) { + IQMAnim& anim = Anims[i]; anim.Name = reader.ReadName(text); + NamedAnimations.Insert(anim.Name, i); + anim.FirstFrame = reader.ReadUInt32(); anim.NumFrames = reader.ReadUInt32(); anim.Framerate = reader.ReadFloat(); @@ -445,6 +448,27 @@ int IQMModel::FindFrame(const char* name, bool nodefault) return FErr_NotFound; } +int IQMModel::FindFirstFrame(FName name) +{ + int * nam = NamedAnimations.CheckKey(name); + if(nam) return Anims[*nam].FirstFrame; + return FErr_NotFound; +} + +int IQMModel::FindLastFrame(FName name) +{ + int * nam = NamedAnimations.CheckKey(name); + if(nam) return Anims[*nam].FirstFrame + Anims[*nam].NumFrames; + return FErr_NotFound; +} + +double IQMModel::FindFramerate(FName name) +{ + int * nam = NamedAnimations.CheckKey(name); + if(nam) return Anims[*nam].Framerate; + return FErr_NotFound; +} + void IQMModel::RenderFrame(FModelRenderer* renderer, FGameTexture* skin, int frame1, int frame2, double inter, FTranslationID translation, const FTextureID* surfaceskinids, const TArray& boneData, int boneStartPosition) { renderer->SetupFrame(this, 0, 0, NumVertices, boneData, boneStartPosition); @@ -517,7 +541,26 @@ const TArray* IQMModel::AttachAnimationData() return &TRSData; } -const TArray IQMModel::CalculateBones(int frame1, int frame2, double inter, const TArray* animationData, DBoneComponents* boneComponentData, int index) +static TRS InterpolateBone(const TRS &from, const TRS &to, float t, float invt) +{ + TRS bone; + + bone.translation = from.translation * invt + to.translation * t; + bone.rotation = from.rotation * invt; + + if ((bone.rotation | to.rotation * t) < 0) + { + bone.rotation.X *= -1; bone.rotation.Y *= -1; bone.rotation.Z *= -1; bone.rotation.W *= -1; + } + + bone.rotation += to.rotation * t; + bone.rotation.MakeUnit(); + bone.scaling = from.scaling * invt + to.scaling * t; + + return bone; +} + +const TArray IQMModel::CalculateBones(int frame1, int frame2, float inter, int frame1_prev, float inter1_prev, int frame2_prev, float inter2_prev, const TArray* animationData, DBoneComponents* boneComponentData, int index) { const TArray& animationFrames = animationData ? *animationData : TRSData; if (Joints.Size() > 0) @@ -534,8 +577,13 @@ const TArray IQMModel::CalculateBones(int frame1, int frame2, double i int offset1 = frame1 * numbones; int offset2 = frame2 * numbones; - float t = (float)inter; - float invt = 1.0f - t; + + int offset1_1 = frame1_prev * numbones; + int offset2_1 = frame2_prev * numbones; + + float invt = 1.0f - inter; + float invt1 = 1.0f - inter1_prev; + float invt2 = 1.0f - inter2_prev; float swapYZ[16] = { 0.0f }; swapYZ[0 + 0 * 4] = 1.0f; @@ -547,19 +595,26 @@ const TArray IQMModel::CalculateBones(int frame1, int frame2, double i TArray modifiedBone(numbones, true); for (int i = 0; i < numbones; i++) { - TRS bone; - TRS from = animationFrames[offset1 + i]; - TRS to = animationFrames[offset2 + i]; + TRS prev; - bone.translation = from.translation * invt + to.translation * t; - bone.rotation = from.rotation * invt; - if ((bone.rotation | to.rotation * t) < 0) + if(frame1 >= 0 && (frame1_prev >= 0 || inter1_prev < 0)) { - bone.rotation.X *= -1; bone.rotation.Y *= -1; bone.rotation.Z *= -1; bone.rotation.W *= -1; + prev = inter1_prev < 0 ? animationFrames[offset1 + i] : InterpolateBone(animationFrames[offset1_1 + i], animationFrames[offset1 + i], inter1_prev, invt1); + } + + TRS next; + + if(frame2 >= 0 && (frame2_prev >= 0 || inter2_prev < 0)) + { + next = inter2_prev < 0 ? animationFrames[offset2 + i] : InterpolateBone(animationFrames[offset2_1 + i], animationFrames[offset2 + i], inter2_prev, invt2); + } + + TRS bone; + + if(frame1 >= 0 || inter < 0) + { + bone = inter < 0 ? animationFrames[offset1 + i] : InterpolateBone(prev, next , inter, invt); } - bone.rotation += to.rotation * t; - bone.rotation.MakeUnit(); - bone.scaling = from.scaling * invt + to.scaling * t; if (Joints[i].Parent >= 0 && modifiedBone[Joints[i].Parent]) { diff --git a/source/common/objects/dobject.h b/source/common/objects/dobject.h index 4a77ed980..aed223071 100644 --- a/source/common/objects/dobject.h +++ b/source/common/objects/dobject.h @@ -179,8 +179,6 @@ public: \ #include "dobjgc.h" -class AActor; - class DObject { public: diff --git a/source/common/objects/dobjgc.h b/source/common/objects/dobjgc.h index 25e27bfb3..969551d37 100644 --- a/source/common/objects/dobjgc.h +++ b/source/common/objects/dobjgc.h @@ -210,8 +210,8 @@ class TObjPtr { union { - T pp; - DObject *o; + mutable T pp; + mutable DObject *o; }; public: @@ -273,16 +273,22 @@ public: { return GC::ReadBarrier(pp); } - constexpr bool operator!=(T u) noexcept + + constexpr const T operator->() const noexcept + { + return GC::ReadBarrier(pp); + } + + constexpr bool operator!=(T u) const noexcept { return GC::ReadBarrier(o) != u; } - constexpr bool operator==(T u) noexcept + constexpr bool operator==(T u) const noexcept { return GC::ReadBarrier(o) == u; } - constexpr bool operator==(TObjPtr u) noexcept + constexpr bool operator==(TObjPtr u) const noexcept { return ForceGet() == u.ForceGet(); } diff --git a/source/common/platform/posix/sdl/i_system.cpp b/source/common/platform/posix/sdl/i_system.cpp index 58a6a2f37..d1f465467 100644 --- a/source/common/platform/posix/sdl/i_system.cpp +++ b/source/common/platform/posix/sdl/i_system.cpp @@ -218,20 +218,21 @@ void RedrawProgressBar(int CurPos, int MaxPos) CleanProgressBar(); struct winsize sizeOfWindow; ioctl(STDOUT_FILENO, TIOCGWINSZ, &sizeOfWindow); + int windowColClamped = std::min((int)sizeOfWindow.ws_col, 512); double progVal = std::clamp((double)CurPos / (double)MaxPos,0.0,1.0); - int curProgVal = std::clamp(int(sizeOfWindow.ws_col * progVal),0,(int)sizeOfWindow.ws_col); + int curProgVal = std::clamp(int(windowColClamped * progVal),0,windowColClamped); char progressBuffer[512]; memset(progressBuffer,'.',512); - progressBuffer[sizeOfWindow.ws_col - 1] = 0; + progressBuffer[windowColClamped - 1] = 0; int lengthOfStr = 0; while (curProgVal-- > 0) { progressBuffer[lengthOfStr++] = '='; - if (lengthOfStr >= sizeOfWindow.ws_col - 1) break; + if (lengthOfStr >= windowColClamped - 1) break; } - fprintf(stdout, "\0337\033[%d;%dH\033[2K[%s\033[%d;%dH]\0338", sizeOfWindow.ws_row, 0, progressBuffer, sizeOfWindow.ws_row, sizeOfWindow.ws_col); + fprintf(stdout, "\0337\033[%d;%dH\033[2K[%s\033[%d;%dH]\0338", sizeOfWindow.ws_row, 0, progressBuffer, sizeOfWindow.ws_row, windowColClamped); fflush(stdout); ProgressBarCurPos = CurPos; ProgressBarMaxPos = MaxPos; diff --git a/source/common/platform/win32/i_system.cpp b/source/common/platform/win32/i_system.cpp index 6da33867f..568a18a21 100644 --- a/source/common/platform/win32/i_system.cpp +++ b/source/common/platform/win32/i_system.cpp @@ -850,37 +850,6 @@ FString I_GetLongPathName(const FString &shortpath) return longpath; } -#ifdef _USING_V110_SDK71_ -//========================================================================== -// -// _stat64i32 -// -// Work around an issue where stat() function doesn't work -// with Windows XP compatible toolset. -// It uses GetFileInformationByHandleEx() which requires Windows Vista. -// -//========================================================================== - -int _wstat64i32(const wchar_t *path, struct _stat64i32 *buffer) -{ - WIN32_FILE_ATTRIBUTE_DATA data; - if(!GetFileAttributesExW(path, GetFileExInfoStandard, &data)) - return -1; - - buffer->st_ino = 0; - buffer->st_mode = ((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? S_IFDIR : S_IFREG)| - ((data.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ? S_IREAD : S_IREAD|S_IWRITE); - buffer->st_dev = buffer->st_rdev = 0; - buffer->st_nlink = 1; - buffer->st_uid = 0; - buffer->st_gid = 0; - buffer->st_size = data.nFileSizeLow; - buffer->st_atime = (*(uint64_t*)&data.ftLastAccessTime) / 10000000 - 11644473600LL; - buffer->st_mtime = (*(uint64_t*)&data.ftLastWriteTime) / 10000000 - 11644473600LL; - buffer->st_ctime = (*(uint64_t*)&data.ftCreationTime) / 10000000 - 11644473600LL; - return 0; -} -#endif struct NumaNode { diff --git a/source/common/rendering/v_video.cpp b/source/common/rendering/v_video.cpp index 7c79e8bea..869d99219 100644 --- a/source/common/rendering/v_video.cpp +++ b/source/common/rendering/v_video.cpp @@ -104,6 +104,7 @@ CUSTOM_CVAR(Int, vid_preferbackend, 1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_N #ifdef HAVE_GLES2 case 3: case 2: + self = 2; Printf("Selecting OpenGLES 2.0 backend...\n"); break; #endif @@ -122,7 +123,7 @@ CUSTOM_CVAR(Int, vid_preferbackend, 1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_N int V_GetBackend() { int v = vid_preferbackend; - if (v == 3) v = 2; + if (v == 3) vid_preferbackend = v = 2; else if (v < 0 || v > 3) v = 0; return v; } diff --git a/source/common/scripting/backend/codegen.cpp b/source/common/scripting/backend/codegen.cpp index da487fad8..84f7e76b4 100644 --- a/source/common/scripting/backend/codegen.cpp +++ b/source/common/scripting/backend/codegen.cpp @@ -2728,7 +2728,7 @@ FxExpression *FxAssign::Resolve(FCompileContext &ctx) { FArgumentList args; args.Push(Right); - auto call = new FxMemberFunctionCall(Base, NAME_Copy, args, ScriptPosition); + auto call = new FxMemberFunctionCall(Base, NAME_Copy, std::move(args), ScriptPosition); Right = Base = nullptr; delete this; return call->Resolve(ctx); @@ -2756,7 +2756,7 @@ FxExpression *FxAssign::Resolve(FCompileContext &ctx) { FArgumentList args; args.Push(Right); - auto call = new FxMemberFunctionCall(Base, NAME_Copy, args, ScriptPosition); + auto call = new FxMemberFunctionCall(Base, NAME_Copy, std::move(args), ScriptPosition); Right = Base = nullptr; delete this; return call->Resolve(ctx); @@ -3826,6 +3826,16 @@ FxExpression *FxCompareRel::Resolve(FCompileContext& ctx) delete left; left = x; } + else if (left->IsNumeric() && right->ValueType == TypeTranslationID && ctx.Version < MakeVersion(4, 12)) + { + right = new FxTypeCast(right, TypeSInt32, true); + SAFE_RESOLVE(right, ctx); + } + else if (right->IsNumeric() && left->ValueType == TypeTranslationID && ctx.Version < MakeVersion(4, 12)) + { + left = new FxTypeCast(left, TypeSInt32, true); + SAFE_RESOLVE(left, ctx); + } if (left->ValueType == TypeString || right->ValueType == TypeString) { @@ -4118,6 +4128,17 @@ FxExpression *FxCompareEq::Resolve(FCompileContext& ctx) delete left; left = x; } + else if (left->IsNumeric() && right->ValueType == TypeTranslationID && ctx.Version < MakeVersion(4, 12)) + { + right = new FxIntCast(right, true, true); + SAFE_RESOLVE(right, ctx); + } + else if (right->IsNumeric() && left->ValueType == TypeTranslationID && ctx.Version < MakeVersion(4, 12)) + { + left = new FxTypeCast(left, TypeSInt32, true); + SAFE_RESOLVE(left, ctx); + } + // Special cases: Compare strings and names with names, sounds, colors, state labels and class types. // These are all types a string can be implicitly cast into, so for convenience, so they should when doing a comparison. if ((left->ValueType == TypeString || left->ValueType == TypeName) && @@ -8181,7 +8202,7 @@ static bool CheckFunctionCompatiblity(FScriptPosition &ScriptPosition, PFunction // //========================================================================== -FxFunctionCall::FxFunctionCall(FName methodname, FName rngname, FArgumentList &args, const FScriptPosition &pos) +FxFunctionCall::FxFunctionCall(FName methodname, FName rngname, FArgumentList &&args, const FScriptPosition &pos) : FxExpression(EFX_FunctionCall, pos) { MethodName = methodname; @@ -8608,7 +8629,7 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx) // //========================================================================== -FxMemberFunctionCall::FxMemberFunctionCall(FxExpression *self, FName methodname, FArgumentList &args, const FScriptPosition &pos) +FxMemberFunctionCall::FxMemberFunctionCall(FxExpression *self, FName methodname, FArgumentList &&args, const FScriptPosition &pos) : FxExpression(EFX_MemberFunctionCall, pos) { Self = self; @@ -9153,7 +9174,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) if (a->IsMap()) { // Copy and Move must turn their parameter into a pointer to the backing struct type. - auto o = static_cast(a->ValueType); + auto o = static_cast(a->ValueType); auto backingtype = o->BackingType; if (mapKeyType != o->KeyType || mapValueType != o->ValueType) { @@ -11361,12 +11382,14 @@ ExpEmit FxForLoop::Emit(VMFunctionBuilder *build) // //========================================================================== -FxForEachLoop::FxForEachLoop(FName vn, FxExpression* arrayvar, FxExpression* arrayvar2, FxExpression* code, const FScriptPosition& pos) - : FxLoopStatement(EFX_ForEachLoop, pos), loopVarName(vn), Array(arrayvar), Array2(arrayvar2), Code(code) +FxForEachLoop::FxForEachLoop(FName vn, FxExpression* arrayvar, FxExpression* arrayvar2, FxExpression* arrayvar3, FxExpression* arrayvar4, FxExpression* code, const FScriptPosition& pos) + : FxLoopStatement(EFX_ForEachLoop, pos), loopVarName(vn), Array(arrayvar), Array2(arrayvar2), Array3(arrayvar3), Array4(arrayvar4), Code(code) { ValueType = TypeVoid; if (Array != nullptr) Array->NeedResult = false; if (Array2 != nullptr) Array2->NeedResult = false; + if (Array3 != nullptr) Array3->NeedResult = false; + if (Array4 != nullptr) Array4->NeedResult = false; if (Code != nullptr) Code->NeedResult = false; } @@ -11374,57 +11397,347 @@ FxForEachLoop::~FxForEachLoop() { SAFE_DELETE(Array); SAFE_DELETE(Array2); + SAFE_DELETE(Array3); + SAFE_DELETE(Array4); SAFE_DELETE(Code); } +extern bool IsGameSpecificForEachLoop(FxForEachLoop *); +extern FxExpression * ResolveGameSpecificForEachLoop(FxForEachLoop *); + FxExpression* FxForEachLoop::DoResolve(FCompileContext& ctx) { CHECKRESOLVED(); SAFE_RESOLVE(Array, ctx); SAFE_RESOLVE(Array2, ctx); + SAFE_RESOLVE(Array3, ctx); + SAFE_RESOLVE(Array4, ctx); - // Instead of writing a new code generator for this, convert this into - // - // int @size = array.Size(); - // for(int @i = 0; @i < @size; @i++) - // { - // let var = array[i]; - // body - // } - // and let the existing 'for' loop code sort out the rest. - FName sizevar = "@size"; - FName itvar = "@i"; - FArgumentList al; - auto block = new FxCompoundStatement(ScriptPosition); - auto arraysize = new FxMemberFunctionCall(Array, NAME_Size, al, ScriptPosition); - auto size = new FxLocalVariableDeclaration(TypeSInt32, sizevar, arraysize, 0, ScriptPosition); - auto it = new FxLocalVariableDeclaration(TypeSInt32, itvar, new FxConstant(0, ScriptPosition), 0, ScriptPosition); - block->Add(size); - block->Add(it); + if(Array->ValueType->isMap() || Array->ValueType->isMapIterator()) + { + auto mapLoop = new FxTwoArgForEachLoop(NAME_None, loopVarName, Array, Array2, Array3, Array4, Code, ScriptPosition); + Array = Array2 = Array3 = Array4 = Code = nullptr; + delete this; + return mapLoop->Resolve(ctx); + } + else if(IsGameSpecificForEachLoop(this)) + { + return ResolveGameSpecificForEachLoop(this)->Resolve(ctx); + } + else + { + // Instead of writing a new code generator for this, convert this into + // + // int @size = array.Size(); + // for(int @i = 0; @i < @size; @i++) + // { + // let var = array[i]; + // body + // } + // and let the existing 'for' loop code sort out the rest. - auto cit = new FxLocalVariable(it, ScriptPosition); - auto csiz = new FxLocalVariable(size, ScriptPosition); - auto comp = new FxCompareRel('<', cit, csiz); // new FxIdentifier(itvar, ScriptPosition), new FxIdentifier(sizevar, ScriptPosition)); + FName sizevar = "@size"; + FName itvar = "@i"; - auto iit = new FxLocalVariable(it, ScriptPosition); - auto bump = new FxPreIncrDecr(iit, TK_Incr); + auto block = new FxCompoundStatement(ScriptPosition); + auto arraysize = new FxMemberFunctionCall(Array, NAME_Size, {}, ScriptPosition); + auto size = new FxLocalVariableDeclaration(TypeSInt32, sizevar, arraysize, 0, ScriptPosition); + auto it = new FxLocalVariableDeclaration(TypeSInt32, itvar, new FxConstant(0, ScriptPosition), 0, ScriptPosition); + block->Add(size); + block->Add(it); - auto ait = new FxLocalVariable(it, ScriptPosition); - auto access = new FxArrayElement(Array2, ait, true); // Note: Array must be a separate copy because these nodes cannot share the same element. + auto cit = new FxLocalVariable(it, ScriptPosition); + auto csiz = new FxLocalVariable(size, ScriptPosition); + auto comp = new FxCompareRel('<', cit, csiz); // new FxIdentifier(itvar, ScriptPosition), new FxIdentifier(sizevar, ScriptPosition)); - auto assign = new FxLocalVariableDeclaration(TypeAuto, loopVarName, access, 0, ScriptPosition); - auto body = new FxCompoundStatement(ScriptPosition); - body->Add(assign); - body->Add(Code); - auto forloop = new FxForLoop(nullptr, comp, bump, body, ScriptPosition); - block->Add(forloop); - Array2 = Array = nullptr; - Code = nullptr; - delete this; - return block->Resolve(ctx); + auto iit = new FxLocalVariable(it, ScriptPosition); + auto bump = new FxPreIncrDecr(iit, TK_Incr); + + auto ait = new FxLocalVariable(it, ScriptPosition); + auto access = new FxArrayElement(Array2, ait, true); // Note: Array must be a separate copy because these nodes cannot share the same element. + + auto assign = new FxLocalVariableDeclaration(TypeAuto, loopVarName, access, 0, ScriptPosition); + auto body = new FxCompoundStatement(ScriptPosition); + body->Add(assign); + body->Add(Code); + auto forloop = new FxForLoop(nullptr, comp, bump, body, ScriptPosition); + block->Add(forloop); + Array2 = Array = nullptr; + Code = nullptr; + delete this; + return block->Resolve(ctx); + } } +//========================================================================== +// +// FxMapForEachLoop +// +//========================================================================== + +FxTwoArgForEachLoop::FxTwoArgForEachLoop(FName kv, FName vv, FxExpression* mapexpr, FxExpression* mapexpr2, FxExpression* mapexpr3, FxExpression* mapexpr4, FxExpression* code, const FScriptPosition& pos) + : FxExpression(EFX_TwoArgForEachLoop,pos), keyVarName(kv), valueVarName(vv), MapExpr(mapexpr), MapExpr2(mapexpr2), MapExpr3(mapexpr3), MapExpr4(mapexpr4), Code(code) +{ + ValueType = TypeVoid; + if (MapExpr != nullptr) MapExpr->NeedResult = false; + if (MapExpr2 != nullptr) MapExpr2->NeedResult = false; + if (MapExpr3 != nullptr) MapExpr3->NeedResult = false; + if (MapExpr4 != nullptr) MapExpr4->NeedResult = false; + if (Code != nullptr) Code->NeedResult = false; +} + +FxTwoArgForEachLoop::~FxTwoArgForEachLoop() +{ + SAFE_DELETE(MapExpr); + SAFE_DELETE(MapExpr2); + SAFE_DELETE(MapExpr3); + SAFE_DELETE(MapExpr4); + SAFE_DELETE(Code); +} + +extern bool HasGameSpecificTwoArgForEachLoopTypeNames(); +extern const char * GetGameSpecificTwoArgForEachLoopTypeNames(); +extern bool IsGameSpecificTwoArgForEachLoop(FxTwoArgForEachLoop *); +extern FxExpression * ResolveGameSpecificTwoArgForEachLoop(FxTwoArgForEachLoop *); + +FxExpression *FxTwoArgForEachLoop::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(MapExpr, ctx); + SAFE_RESOLVE(MapExpr2, ctx); + SAFE_RESOLVE(MapExpr3, ctx); + SAFE_RESOLVE(MapExpr4, ctx); + + bool is_iterator = false; + + if(IsGameSpecificTwoArgForEachLoop(this)) + { + return ResolveGameSpecificTwoArgForEachLoop(this)->Resolve(ctx); + } + else if(!(MapExpr->ValueType->isMap() || (is_iterator = MapExpr->ValueType->isMapIterator()))) + { + if(HasGameSpecificTwoArgForEachLoopTypeNames()) + { + ScriptPosition.Message(MSG_ERROR, "foreach( k, v : m ) - 'm' must be %s a map, or a map iterator, but is a %s", GetGameSpecificTwoArgForEachLoopTypeNames(), MapExpr->ValueType->DescriptiveName()); + delete this; + return nullptr; + } + else + { + ScriptPosition.Message(MSG_ERROR, "foreach( k, v : m ) - 'm' must be a map or a map iterator, but is a %s", MapExpr->ValueType->DescriptiveName()); + delete this; + return nullptr; + } + } + else if(valueVarName == NAME_None) + { + ScriptPosition.Message(MSG_ERROR, "missing value for foreach( k, v : m )"); + delete this; + return nullptr; + } + + + auto block = new FxCompoundStatement(ScriptPosition); + + auto valType = is_iterator ? static_cast(MapExpr->ValueType)->ValueType : static_cast(MapExpr->ValueType)->ValueType; + auto keyType = is_iterator ? static_cast(MapExpr->ValueType)->KeyType : static_cast(MapExpr->ValueType)->KeyType; + + auto v = new FxLocalVariableDeclaration(valType, valueVarName, nullptr, 0, ScriptPosition); + block->Add(v); + + if(keyVarName != NAME_None) + { + auto k = new FxLocalVariableDeclaration(keyType, keyVarName, nullptr, 0, ScriptPosition); + block->Add(k); + } + + + if(MapExpr->ValueType->isMapIterator()) + { + /* + { + KeyType k; + ValueType v; + if(it.ReInit()) while(it.Next()) + { + k = it.GetKey(); + v = it.GetValue(); + body + } + } + */ + + auto inner_block = new FxCompoundStatement(ScriptPosition); + + if(keyVarName != NAME_None) + { + inner_block->Add(new FxAssign(new FxIdentifier(keyVarName, ScriptPosition), new FxMemberFunctionCall(MapExpr, "GetKey", {}, ScriptPosition), true)); + } + + inner_block->Add(new FxAssign(new FxIdentifier(valueVarName, ScriptPosition), new FxMemberFunctionCall(MapExpr2, "GetValue", {}, ScriptPosition), true)); + inner_block->Add(Code); + + auto reInit = new FxMemberFunctionCall(MapExpr3, "ReInit", {}, ScriptPosition); + block->Add(new FxIfStatement(reInit, new FxWhileLoop(new FxMemberFunctionCall(MapExpr4, "Next", {}, ScriptPosition), inner_block, ScriptPosition), nullptr, ScriptPosition)); + + MapExpr = MapExpr2 = MapExpr3 = MapExpr4 = Code = nullptr; + delete this; + return block->Resolve(ctx); + } + else + { + /* + { + KeyType k; + ValueType v; + MapIterator @it; + @it.Init(map); + while(@it.Next()) + { + k = @it.GetKey(); + v = @it.GetValue(); + body + } + } + */ + + PType * itType = NewMapIterator(keyType, valType); + auto it = new FxLocalVariableDeclaration(itType, "@it", nullptr, 0, ScriptPosition); + block->Add(it); + + FArgumentList al_map; + al_map.Push(MapExpr); + + block->Add(new FxMemberFunctionCall(new FxIdentifier("@it", ScriptPosition), "Init", std::move(al_map), ScriptPosition)); + + auto inner_block = new FxCompoundStatement(ScriptPosition); + + if(keyVarName != NAME_None) + { + inner_block->Add(new FxAssign(new FxIdentifier(keyVarName, ScriptPosition), new FxMemberFunctionCall(new FxIdentifier("@it", ScriptPosition), "GetKey", {}, ScriptPosition), true)); + } + inner_block->Add(new FxAssign(new FxIdentifier(valueVarName, ScriptPosition), new FxMemberFunctionCall(new FxIdentifier("@it", ScriptPosition), "GetValue", {}, ScriptPosition), true)); + inner_block->Add(Code); + + block->Add(new FxWhileLoop(new FxMemberFunctionCall(new FxIdentifier("@it", ScriptPosition), "Next", {}, ScriptPosition), inner_block, ScriptPosition)); + + delete MapExpr2; + delete MapExpr3; + delete MapExpr4; + MapExpr = MapExpr2 = MapExpr3 = MapExpr4 = Code = nullptr; + delete this; + return block->Resolve(ctx); + } +} + + +//========================================================================== +// +// FxThreeArgForEachLoop +// +//========================================================================== + +FxThreeArgForEachLoop::FxThreeArgForEachLoop(FName vv, FName pv, FName fv, FxExpression* blockiteartorexpr, FxExpression* code, const FScriptPosition& pos) + : FxExpression(EFX_ThreeArgForEachLoop, pos), varVarName(vv), posVarName(pv), flagsVarName(fv), BlockIteratorExpr(blockiteartorexpr), Code(code) +{ + ValueType = TypeVoid; + if (BlockIteratorExpr != nullptr) BlockIteratorExpr->NeedResult = false; + if (Code != nullptr) Code->NeedResult = false; +} + +FxThreeArgForEachLoop::~FxThreeArgForEachLoop() +{ + SAFE_DELETE(BlockIteratorExpr); + SAFE_DELETE(Code); +} + +extern bool HasGameSpecificThreeArgForEachLoopTypeNames(); +extern const char * GetGameSpecificThreeArgForEachLoopTypeNames(); +extern bool IsGameSpecificThreeArgForEachLoop(FxThreeArgForEachLoop *); +extern FxExpression * ResolveGameSpecificThreeArgForEachLoop(FxThreeArgForEachLoop *); + +FxExpression *FxThreeArgForEachLoop::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(BlockIteratorExpr, ctx); + + + if(IsGameSpecificThreeArgForEachLoop(this)) + { + return ResolveGameSpecificThreeArgForEachLoop(this)->Resolve(ctx); + } + else + { + //put any non-game-specific typed for-each loops here + } + + if(HasGameSpecificThreeArgForEachLoopTypeNames()) + { + ScriptPosition.Message(MSG_ERROR, "foreach( a, b, c : it ) - 'it' must be % but is a %s", GetGameSpecificThreeArgForEachLoopTypeNames(), BlockIteratorExpr->ValueType->DescriptiveName()); + delete this; + return nullptr; + } + else + { + ScriptPosition.Message(MSG_ERROR, "foreach( a, b, c : it ) - three-arg foreach loops not supported"); + delete this; + return nullptr; + } +} + +//========================================================================== +// +// FxCastForEachLoop +// +//========================================================================== + +FxTypedForEachLoop::FxTypedForEachLoop(FName cv, FName vv, FxExpression* castiteartorexpr, FxExpression* code, const FScriptPosition& pos) + : FxExpression(EFX_TypedForEachLoop, pos), className(cv), varName(vv), Expr(castiteartorexpr), Code(code) +{ + ValueType = TypeVoid; + if (Expr != nullptr) Expr->NeedResult = false; + if (Code != nullptr) Code->NeedResult = false; +} + +FxTypedForEachLoop::~FxTypedForEachLoop() +{ + SAFE_DELETE(Expr); + SAFE_DELETE(Code); +} + +extern bool HasGameSpecificTypedForEachLoopTypeNames(); +extern const char * GetGameSpecificTypedForEachLoopTypeNames(); +extern bool IsGameSpecificTypedForEachLoop(FxTypedForEachLoop *); +extern FxExpression * ResolveGameSpecificTypedForEachLoop(FxTypedForEachLoop *); + +FxExpression *FxTypedForEachLoop::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(Expr, ctx); + + if(IsGameSpecificTypedForEachLoop(this)) + { + return ResolveGameSpecificTypedForEachLoop(this)->Resolve(ctx); + } + else + { + //put any non-game-specific typed for-each loops here + } + + if(HasGameSpecificTypedForEachLoopTypeNames()) + { + ScriptPosition.Message(MSG_ERROR, "foreach(Type var : it ) - 'it' must be % but is a %s",GetGameSpecificTypedForEachLoopTypeNames(), Expr->ValueType->DescriptiveName()); + delete this; + return nullptr; + } + else + { + ScriptPosition.Message(MSG_ERROR, "foreach(Type var : it ) - typed foreach loops not supported"); + delete this; + return nullptr; + } +} //========================================================================== // @@ -12267,8 +12580,7 @@ FxExpression *FxLocalVariableDeclaration::Resolve(FCompileContext &ctx) if (IsDynamicArray()) { auto stackVar = new FxStackVariable(ValueType, StackOffset, ScriptPosition); - FArgumentList argsList; - clearExpr = new FxMemberFunctionCall(stackVar, "Clear", argsList, ScriptPosition); + clearExpr = new FxMemberFunctionCall(stackVar, "Clear", {}, ScriptPosition); SAFE_RESOLVE(clearExpr, ctx); } @@ -12586,10 +12898,9 @@ FxExpression *FxLocalArrayDeclaration::Resolve(FCompileContext &ctx) else { FArgumentList argsList; - argsList.Clear(); argsList.Push(v); - FxExpression *funcCall = new FxMemberFunctionCall(stackVar, NAME_Push, argsList, (const FScriptPosition) v->ScriptPosition); + FxExpression *funcCall = new FxMemberFunctionCall(stackVar, NAME_Push, std::move(argsList), (const FScriptPosition) v->ScriptPosition); SAFE_RESOLVE(funcCall, ctx); v = funcCall; diff --git a/source/common/scripting/backend/codegen.h b/source/common/scripting/backend/codegen.h index 3f73a09c5..1b51eb151 100644 --- a/source/common/scripting/backend/codegen.h +++ b/source/common/scripting/backend/codegen.h @@ -275,6 +275,9 @@ enum EFxType EFX_DoWhileLoop, EFX_ForLoop, EFX_ForEachLoop, + EFX_TwoArgForEachLoop, + EFX_ThreeArgForEachLoop, + EFX_TypedForEachLoop, EFX_JumpStatement, EFX_ReturnStatement, EFX_ClassTypeCast, @@ -1621,7 +1624,7 @@ public: FName MethodName; FArgumentList ArgList; - FxFunctionCall(FName methodname, FName rngname, FArgumentList &args, const FScriptPosition &pos); + FxFunctionCall(FName methodname, FName rngname, FArgumentList &&args, const FScriptPosition &pos); ~FxFunctionCall(); FxExpression *Resolve(FCompileContext&); }; @@ -1638,10 +1641,11 @@ class FxMemberFunctionCall : public FxExpression FxExpression *Self; FName MethodName; FArgumentList ArgList; + bool ResolveSelf; public: - FxMemberFunctionCall(FxExpression *self, FName methodname, FArgumentList &args, const FScriptPosition &pos); + FxMemberFunctionCall(FxExpression *self, FName methodname, FArgumentList &&args, const FScriptPosition &pos); ~FxMemberFunctionCall(); FxExpression *Resolve(FCompileContext&); }; @@ -2069,17 +2073,83 @@ public: class FxForEachLoop : public FxLoopStatement { +public: FName loopVarName; FxExpression* Array; FxExpression* Array2; + FxExpression* Array3; + FxExpression* Array4; FxExpression* Code; -public: - FxForEachLoop(FName vn, FxExpression* arrayvar, FxExpression* arrayvar2, FxExpression* code, const FScriptPosition& pos); + FxForEachLoop(FName vn, FxExpression* arrayvar, FxExpression* arrayvar2, FxExpression* arrayvar3, FxExpression* arrayvar4, FxExpression* code, const FScriptPosition& pos); ~FxForEachLoop(); FxExpression* DoResolve(FCompileContext&); }; +//========================================================================== +// +// FxTwoArgForEachLoop +// +//========================================================================== + +class FxTwoArgForEachLoop : public FxExpression +{ +public: + FName keyVarName; + FName valueVarName; + FxExpression* MapExpr; + FxExpression* MapExpr2; + FxExpression* MapExpr3; + FxExpression* MapExpr4; + FxExpression* Code; + + FxTwoArgForEachLoop(FName kv, FName vv, FxExpression* mapexpr, FxExpression* mapexpr2, FxExpression* mapexpr3, FxExpression* mapexpr4, FxExpression* code, const FScriptPosition& pos); + ~FxTwoArgForEachLoop(); + FxExpression *Resolve(FCompileContext&); + //ExpEmit Emit(VMFunctionBuilder *build); This node is transformed, so it won't ever be emitted itself +}; + +//========================================================================== +// +// FxThreeArgForEachLoop +// +//========================================================================== + +class FxThreeArgForEachLoop : public FxExpression +{ +public: + FName varVarName; + FName posVarName; + FName flagsVarName; + FxExpression* BlockIteratorExpr; + FxExpression* Code; + + FxThreeArgForEachLoop(FName vv, FName pv, FName fv, FxExpression* blockiteartorexpr, FxExpression* code, const FScriptPosition& pos); + ~FxThreeArgForEachLoop(); + FxExpression *Resolve(FCompileContext&); + //ExpEmit Emit(VMFunctionBuilder *build); This node is transformed, so it won't ever be emitted itself +}; + +//========================================================================== +// +// FxTypedForEachLoop +// +//========================================================================== + +class FxTypedForEachLoop : public FxExpression +{ +public: + FName className; + FName varName; + FxExpression* Expr; + FxExpression* Code; + + FxTypedForEachLoop(FName cv, FName vv, FxExpression* castiteartorexpr, FxExpression* code, const FScriptPosition& pos); + ~FxTypedForEachLoop(); + FxExpression *Resolve(FCompileContext&); + //ExpEmit Emit(VMFunctionBuilder *build); This node is transformed, so it won't ever be emitted itself +}; + //========================================================================== // // FxJumpStatement diff --git a/source/common/scripting/backend/vmbuilder.cpp b/source/common/scripting/backend/vmbuilder.cpp index 259055dc9..71a766d9a 100644 --- a/source/common/scripting/backend/vmbuilder.cpp +++ b/source/common/scripting/backend/vmbuilder.cpp @@ -41,6 +41,9 @@ CVAR(Bool, strictdecorate, false, CVAR_GLOBALCONFIG | CVAR_ARCHIVE) +EXTERN_CVAR(Bool, vm_jit) +EXTERN_CVAR(Bool, vm_jit_aot) + struct VMRemap { uint8_t altOp, kReg, kType; @@ -928,6 +931,13 @@ void FFunctionBuildList::Build() disasmdump.Write(sfunc, item.PrintableName); sfunc->Unsafe = ctx.Unsafe; + + #if HAVE_VM_JIT + if(vm_jit && vm_jit_aot) + { + sfunc->JitCompile(); + } + #endif } catch (CRecoverableError &err) { @@ -1094,8 +1104,6 @@ void FunctionCallEmitter::AddParameterStringConst(const FString &konst) }); } -EXTERN_CVAR(Bool, vm_jit) - ExpEmit FunctionCallEmitter::EmitCall(VMFunctionBuilder *build, TArray *ReturnRegs) { unsigned paramcount = 0; diff --git a/source/common/scripting/core/imports.cpp b/source/common/scripting/core/imports.cpp index eed84980a..ff6d7ceba 100644 --- a/source/common/scripting/core/imports.cpp +++ b/source/common/scripting/core/imports.cpp @@ -147,6 +147,24 @@ VMFunction *FindVMFunction(PClass *cls, const char *name) } +//========================================================================== +// +// Find an action function in AActor's table from a qualified name +// This cannot search in structs. sorry. :( +// +//========================================================================== + +VMFunction* FindVMFunction( const char* name) +{ + auto p = strchr(name, '.'); + if (p == nullptr) return nullptr; + std::string clsname(name, p - name); + auto cls = PClass::FindClass(clsname.c_str()); + if (cls == nullptr) return nullptr; + return FindVMFunction(cls, p + 1); +} + + //========================================================================== // // Sorting helpers diff --git a/source/common/scripting/core/types.cpp b/source/common/scripting/core/types.cpp index b9949a5ea..1fcd244d8 100644 --- a/source/common/scripting/core/types.cpp +++ b/source/common/scripting/core/types.cpp @@ -42,6 +42,8 @@ #include "textureid.h" #include "maps.h" #include "palettecontainer.h" +#include "texturemanager.h" +#include "i_interface.h" FTypeTable TypeTable; @@ -1659,7 +1661,8 @@ PClassPointer::PClassPointer(PClass *restrict) loadOp = OP_LP; storeOp = OP_SP; Flags |= TYPE_ClassPointer; - mVersion = restrict->VMType->mVersion; + if (restrict) mVersion = restrict->VMType->mVersion; + else mVersion = 0; } //========================================================================== @@ -2549,9 +2552,63 @@ static void PMapValueWriter(FSerializer &ar, const M *map, const PMap *m) } else if constexpr(std::is_same_v) { - FString key; - key.Format("%u",p->Key); - m->ValueType->WriteValue(ar,key.GetChars(),static_cast(&p->Value)); + if(m->KeyType->Flags & 8 /*TYPE_IntNotInt*/) + { + if(m->KeyType == TypeName) + { + m->ValueType->WriteValue(ar,FName(ENamedName(p->Key)).GetChars(),static_cast(&p->Value)); + } + else if(m->KeyType == TypeSound) + { + m->ValueType->WriteValue(ar,soundEngine->GetSoundName(FSoundID::fromInt(p->Key)),static_cast(&p->Value)); + } + else if(m->KeyType == TypeTextureID) + { + if(!!(p->Key & 0x8000000)) + { // invalid + m->ValueType->WriteValue(ar,"invalid",static_cast(&p->Value)); + } + else if(p->Key == 0 || p->Key >= TexMan.NumTextures()) + { // null + m->ValueType->WriteValue(ar,"null",static_cast(&p->Value)); + } + else + { + FTextureID tid; + tid.SetIndex(p->Key); + FGameTexture *tex = TexMan.GetGameTexture(tid); + int lump = tex->GetSourceLump(); + unsigned useType = static_cast(tex->GetUseType()); + + FString name; + + if (TexMan.GetLinkedTexture(lump) == tex) + { + name = fileSystem.GetFileFullName(lump); + } + else + { + name = tex->GetName().GetChars(); + } + + name.AppendFormat(":%u",useType); + + m->ValueType->WriteValue(ar,name.GetChars(),static_cast(&p->Value)); + } + } + else + { // bool/color/enum/sprite/translationID + FString key; + key.Format("%u",p->Key); + m->ValueType->WriteValue(ar,key.GetChars(),static_cast(&p->Value)); + } + } + else + { + FString key; + key.Format("%u",p->Key); + m->ValueType->WriteValue(ar,key.GetChars(),static_cast(&p->Value)); + } } //else unknown key type } @@ -2584,20 +2641,85 @@ static bool PMapValueReader(FSerializer &ar, M *map, const PMap *m) const char * k; while((k = ar.GetKey())) { - typename M::ValueType * val; + typename M::ValueType * val = nullptr; if constexpr(std::is_same_v) { val = &map->InsertNew(k); } else if constexpr(std::is_same_v) { - FString s(k); - if(!s.IsInt()) + if(m->KeyType->Flags & 8 /*TYPE_IntNotInt*/) { - ar.EndObject(); - return false; + if(m->KeyType == TypeName) + { + val = &map->InsertNew(FName(k).GetIndex()); + } + else if(m->KeyType == TypeSound) + { + val = &map->InsertNew(S_FindSound(k).index()); + } + else if(m->KeyType == TypeTextureID) + { + FString s(k); + FTextureID tex; + if(s.Compare("invalid") == 0) + { + tex.SetInvalid(); + } + else if(s.Compare("null") == 0) + { + tex.SetNull(); + } + else + { + ptrdiff_t sep = s.LastIndexOf(":"); + if(sep < 0) + { + ar.EndObject(); + return false; + } + FString texName = s.Left(sep); + FString useType = s.Mid(sep + 1); + + tex = TexMan.GetTextureID(texName.GetChars(), (ETextureType) useType.ToULong()); + } + val = &map->InsertNew(tex.GetIndex()); + } + else if(m->KeyType == TypeTranslationID) + { + FString s(k); + if(!s.IsInt()) + { + ar.EndObject(); + return false; + } + int v = s.ToULong(); + + if (sysCallbacks.RemapTranslation) v = sysCallbacks.RemapTranslation(FTranslationID::fromInt(v)).index(); + + val = &map->InsertNew(v); + } + else + { // bool/color/enum/sprite + FString s(k); + if(!s.IsInt()) + { + ar.EndObject(); + return false; + } + val = &map->InsertNew(static_cast(s.ToULong())); + } + } + else + { + FString s(k); + if(!s.IsInt()) + { + ar.EndObject(); + return false; + } + val = &map->InsertNew(static_cast(s.ToULong())); } - val = &map->InsertNew(static_cast(s.ToULong())); } if (!m->ValueType->ReadValue(ar,nullptr,static_cast(val))) { diff --git a/source/common/scripting/core/types.h b/source/common/scripting/core/types.h index 369df05c8..e892a8b12 100644 --- a/source/common/scripting/core/types.h +++ b/source/common/scripting/core/types.h @@ -742,6 +742,7 @@ extern PPointer *TypeVoidPtr; extern PPointer* TypeRawFunction; extern PPointer* TypeVMFunction; + inline FString &DObject::StringVar(FName field) { return *(FString*)ScriptVar(field, TypeString); diff --git a/source/common/scripting/frontend/ast.cpp b/source/common/scripting/frontend/ast.cpp index 2841c1643..ba91077af 100644 --- a/source/common/scripting/frontend/ast.cpp +++ b/source/common/scripting/frontend/ast.cpp @@ -983,6 +983,53 @@ static void PrintArrayIterationStmt(FLispString &out, const ZCC_TreeNode *node) out.Close(); } +static void PrintTwoArgIterationStmt(FLispString &out, const ZCC_TreeNode *node) +{ + auto inode = (ZCC_TwoArgIterationStmt *)node; + out.Break(); + out.Open("map-iteration-stmt"); + PrintVarName(out, inode->ItKey); + out.Break(); + PrintVarName(out, inode->ItValue); + out.Break(); + PrintNodes(out, inode->ItMap); + out.Break(); + PrintNodes(out, inode->LoopStatement); + out.Close(); +} + +static void PrintThreeArgIterationStmt(FLispString &out, const ZCC_TreeNode *node) +{ + auto inode = (ZCC_ThreeArgIterationStmt *)node; + out.Break(); + out.Open("block-iteration-stmt"); + PrintVarName(out, inode->ItVar); + out.Break(); + PrintVarName(out, inode->ItPos); + out.Break(); + PrintVarName(out, inode->ItFlags); + out.Break(); + PrintNodes(out, inode->ItBlock); + out.Break(); + PrintNodes(out, inode->LoopStatement); + out.Close(); +} + +static void PrintTypedIterationStmt(FLispString &out, const ZCC_TreeNode *node) +{ + auto inode = (ZCC_TypedIterationStmt *)node; + out.Break(); + out.Open("cast-iteration-stmt"); + PrintVarName(out, inode->ItType); + out.Break(); + PrintVarName(out, inode->ItVar); + out.Break(); + PrintNodes(out, inode->ItExpr); + out.Break(); + PrintNodes(out, inode->LoopStatement); + out.Close(); +} + static const NodePrinterFunc TreeNodePrinter[] = { PrintIdentifier, @@ -1050,6 +1097,9 @@ static const NodePrinterFunc TreeNodePrinter[] = PrintMixinDef, PrintMixinStmt, PrintArrayIterationStmt, + PrintTwoArgIterationStmt, + PrintThreeArgIterationStmt, + PrintTypedIterationStmt, }; FString ZCC_PrintAST(const ZCC_TreeNode *root) diff --git a/source/common/scripting/frontend/zcc-parse.lemon b/source/common/scripting/frontend/zcc-parse.lemon index 6af598b3c..199771949 100644 --- a/source/common/scripting/frontend/zcc-parse.lemon +++ b/source/common/scripting/frontend/zcc-parse.lemon @@ -378,6 +378,15 @@ flag_def(X) ::= FLAGDEF(T) IDENTIFIER(A) COLON IDENTIFIER(B) COMMA INTCONST(C) S X = def; } +flag_def(X) ::= FLAGDEF(T) INTERNAL IDENTIFIER(A) COLON IDENTIFIER(B) COMMA INTCONST(C) SEMICOLON. +{ + NEW_AST_NODE(FlagDef,def,T); + def->NodeName = A.Name(); + def->RefName = B.Name(); + def->BitValue = C.Int | 0x10000; + X = def; +} + identifier_list(X) ::= IDENTIFIER(A). { @@ -437,6 +446,7 @@ struct_member(X) ::= declarator(A). { X = A; /*X-overwrites-A*/ } struct_member(X) ::= enum_def(A). { X = A; /*X-overwrites-A*/ } struct_member(X) ::= const_def(A). { X = A; /*X-overwrites-A*/ } struct_member(X) ::= staticarray_statement(A). { X = A; /*X-overwrites-A*/ } +struct_member(X) ::= flag_def(A). { X = A; /*X-overwrites-A*/ } /*----- Constant Definition ------*/ /* Like UnrealScript, a constant's type is implied by its value's type. */ @@ -1946,6 +1956,9 @@ statement(X) ::= expression_statement(A) SEMICOLON. { X = A; /*X-overwrites-A*/ statement(X) ::= selection_statement(X). statement(X) ::= iteration_statement(X). statement(X) ::= array_iteration_statement(X). +statement(X) ::= two_arg_iteration_statement(X). +statement(X) ::= three_arg_iteration_statement(X). +statement(X) ::= typed_iteration_statement(X). statement(X) ::= jump_statement(X). statement(X) ::= assign_statement(A) SEMICOLON. { X = A; /*X-overwrites-A*/ } statement(X) ::= assign_decl_statement(A) SEMICOLON.{ X = A; /*X-overwrites-A*/ } @@ -2115,6 +2128,43 @@ array_iteration_statement(X) ::= FOREACH(T) LPAREN variable_name(IN) COLON expr( X = iter; } +%type two_arg_iteration_statement{ZCC_Statement *} + +two_arg_iteration_statement(X) ::= FOREACH(T) LPAREN variable_name(KEY) COMMA variable_name(VAL) COLON expr(EX) RPAREN statement(ST). +{ + NEW_AST_NODE(TwoArgIterationStmt, iter, T); + iter->ItKey = KEY; + iter->ItValue = VAL; + iter->ItMap = EX; + iter->LoopStatement = ST; + X = iter; +} + +%type three_arg_iteration_statement{ZCC_Statement *} + +three_arg_iteration_statement(X) ::= FOREACH(T) LPAREN variable_name(VAR) COMMA variable_name(POS) COMMA variable_name(FLAGS) COLON expr(EX) RPAREN statement(ST). +{ + NEW_AST_NODE(ThreeArgIterationStmt, iter, T); + iter->ItVar = VAR; + iter->ItPos = POS; + iter->ItFlags = FLAGS; + iter->ItBlock = EX; + iter->LoopStatement = ST; + X = iter; +} + +%type typed_iteration_statement{ZCC_Statement *} + +typed_iteration_statement(X) ::= FOREACH(T) LPAREN variable_name(TYPE) variable_name(VAR) COLON expr(EX) RPAREN statement(ST). +{ + NEW_AST_NODE(TypedIterationStmt, iter, T); + iter->ItType = TYPE; + iter->ItVar = VAR; + iter->ItExpr = EX; + iter->LoopStatement = ST; + X = iter; +} + while_or_until(X) ::= WHILE(T). { X.Int = ZCC_WHILE; diff --git a/source/common/scripting/frontend/zcc_compile.cpp b/source/common/scripting/frontend/zcc_compile.cpp index c01935b44..4c3f2bc38 100644 --- a/source/common/scripting/frontend/zcc_compile.cpp +++ b/source/common/scripting/frontend/zcc_compile.cpp @@ -57,6 +57,13 @@ double GetFloatConst(FxExpression *ex, FCompileContext &ctx) return ex ? static_cast(ex)->GetValue().GetFloat() : 0; } +VMFunction* GetFuncConst(FxExpression* ex, FCompileContext& ctx) +{ + ex = new FxTypeCast(ex, TypeVMFunction, false); + ex = ex->Resolve(ctx); + return static_cast(ex ? static_cast(ex)->GetValue().GetPointer() : nullptr); +} + const char * ZCCCompiler::GetStringConst(FxExpression *ex, FCompileContext &ctx) { ex = new FxStringCast(ex); @@ -452,6 +459,11 @@ void ZCCCompiler::ProcessStruct(ZCC_Struct *cnode, PSymbolTreeNode *treenode, ZC } break; + case AST_FlagDef: + cls->FlagDefs.Push(static_cast(node)); + break; + + default: assert(0 && "Unhandled AST node type"); break; @@ -2987,12 +2999,12 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast, bool substitute) { case AST_ExprID: // The function name is a simple identifier. - return new FxFunctionCall(static_cast(fcall->Function)->Identifier, NAME_None, ConvertNodeList(args, fcall->Parameters), *ast); + return new FxFunctionCall(static_cast(fcall->Function)->Identifier, NAME_None, std::move(ConvertNodeList(args, fcall->Parameters)), *ast); case AST_ExprMemberAccess: { auto ema = static_cast(fcall->Function); - return new FxMemberFunctionCall(ConvertNode(ema->Left, true), ema->Right, ConvertNodeList(args, fcall->Parameters), *ast); + return new FxMemberFunctionCall(ConvertNode(ema->Left, true), ema->Right, std::move(ConvertNodeList(args, fcall->Parameters)), *ast); } case AST_ExprBinary: @@ -3002,7 +3014,7 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast, bool substitute) auto binary = static_cast(fcall->Function); if (binary->Left->NodeType == AST_ExprID && binary->Right->NodeType == AST_ExprID) { - return new FxFunctionCall(static_cast(binary->Left)->Identifier, static_cast(binary->Right)->Identifier, ConvertNodeList(args, fcall->Parameters), *ast); + return new FxFunctionCall(static_cast(binary->Left)->Identifier, static_cast(binary->Right)->Identifier, std::move(ConvertNodeList(args, fcall->Parameters)), *ast); } } // fall through if this isn't an array access node. @@ -3376,10 +3388,45 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast, bool substitute) auto iter = static_cast(ast); auto var = iter->ItName->Name; FxExpression* const itArray = ConvertNode(iter->ItArray); - FxExpression* const itArray2 = ConvertNode(iter->ItArray); // the handler needs two copies of this - here's the easiest place to create them. + FxExpression* const itArray2 = ConvertNode(iter->ItArray); + FxExpression* const itArray3 = ConvertNode(iter->ItArray); + FxExpression* const itArray4 = ConvertNode(iter->ItArray); // the handler needs copies of this - here's the easiest place to create them. FxExpression* const body = ConvertImplicitScopeNode(ast, iter->LoopStatement); - return new FxForEachLoop(iter->ItName->Name, itArray, itArray2, body, *ast); + return new FxForEachLoop(iter->ItName->Name, itArray, itArray2, itArray3, itArray4, body, *ast); + } + case AST_TwoArgIterationStmt: + { + auto iter = static_cast(ast); + auto key = iter->ItKey->Name; + auto var = iter->ItValue->Name; + FxExpression* const itMap = ConvertNode(iter->ItMap); + FxExpression* const itMap2 = ConvertNode(iter->ItMap); + FxExpression* const itMap3 = ConvertNode(iter->ItMap); + FxExpression* const itMap4 = ConvertNode(iter->ItMap); + FxExpression* const body = ConvertImplicitScopeNode(ast, iter->LoopStatement); + return new FxTwoArgForEachLoop(key, var, itMap, itMap2, itMap3, itMap4, body, *ast); + } + + case AST_ThreeArgIterationStmt: + { + auto iter = static_cast(ast); + auto var = iter->ItVar->Name; + auto pos = iter->ItPos->Name; + auto flags = iter->ItFlags->Name; + FxExpression* const itBlock = ConvertNode(iter->ItBlock); + FxExpression* const body = ConvertImplicitScopeNode(ast, iter->LoopStatement); + return new FxThreeArgForEachLoop(var, pos, flags, itBlock, body, *ast); + } + + case AST_TypedIterationStmt: + { + auto iter = static_cast(ast); + auto cls = iter->ItType->Name; + auto var = iter->ItVar->Name; + FxExpression* const itExpr = ConvertNode(iter->ItExpr); + FxExpression* const body = ConvertImplicitScopeNode(ast, iter->LoopStatement); + return new FxTypedForEachLoop(cls, var, itExpr, body, *ast); } case AST_IterationStmt: diff --git a/source/common/scripting/frontend/zcc_compile.h b/source/common/scripting/frontend/zcc_compile.h index b6f32018d..19e9f8ff0 100644 --- a/source/common/scripting/frontend/zcc_compile.h +++ b/source/common/scripting/frontend/zcc_compile.h @@ -6,7 +6,6 @@ struct Baggage; struct FPropertyInfo; -class AActor; class FxExpression; typedef TDeletingArray FArgumentList; @@ -23,6 +22,7 @@ struct ZCC_StructWork TArray Fields; TArray Functions; TArray Arrays; + TArray FlagDefs; ZCC_StructWork() { diff --git a/source/common/scripting/frontend/zcc_parser.cpp b/source/common/scripting/frontend/zcc_parser.cpp index 24b2ecb1f..1b7e846fd 100644 --- a/source/common/scripting/frontend/zcc_parser.cpp +++ b/source/common/scripting/frontend/zcc_parser.cpp @@ -1177,6 +1177,46 @@ ZCC_TreeNode *TreeNodeDeepCopy_Internal(ZCC_AST *ast, ZCC_TreeNode *orig, bool c break; } + case AST_TwoArgIterationStmt: + { + TreeNodeDeepCopy_Start(TwoArgIterationStmt); + + // ZCC_TwoArgIterationStmt + copy->ItKey = static_cast(TreeNodeDeepCopy_Internal(ast, origCasted->ItKey, true, copiedNodesList)); + copy->ItValue = static_cast(TreeNodeDeepCopy_Internal(ast, origCasted->ItValue, true, copiedNodesList)); + copy->LoopStatement = static_cast(TreeNodeDeepCopy_Internal(ast, origCasted->LoopStatement, true, copiedNodesList)); + copy->ItMap = static_cast(TreeNodeDeepCopy_Internal(ast, origCasted->ItMap, true, copiedNodesList)); + + break; + } + + case AST_ThreeArgIterationStmt: + { + TreeNodeDeepCopy_Start(ThreeArgIterationStmt); + + // ZCC_TwoArgIterationStmt + copy->ItVar = static_cast(TreeNodeDeepCopy_Internal(ast, origCasted->ItVar, true, copiedNodesList)); + copy->ItPos = static_cast(TreeNodeDeepCopy_Internal(ast, origCasted->ItPos, true, copiedNodesList)); + copy->ItFlags = static_cast(TreeNodeDeepCopy_Internal(ast, origCasted->ItFlags, true, copiedNodesList)); + copy->LoopStatement = static_cast(TreeNodeDeepCopy_Internal(ast, origCasted->LoopStatement, true, copiedNodesList)); + copy->ItBlock = static_cast(TreeNodeDeepCopy_Internal(ast, origCasted->ItBlock, true, copiedNodesList)); + + break; + } + + case AST_TypedIterationStmt: + { + TreeNodeDeepCopy_Start(TypedIterationStmt); + + // ZCC_TwoArgIterationStmt + copy->ItType = static_cast(TreeNodeDeepCopy_Internal(ast, origCasted->ItType, true, copiedNodesList)); + copy->ItVar = static_cast(TreeNodeDeepCopy_Internal(ast, origCasted->ItVar, true, copiedNodesList)); + copy->LoopStatement = static_cast(TreeNodeDeepCopy_Internal(ast, origCasted->LoopStatement, true, copiedNodesList)); + copy->ItExpr = static_cast(TreeNodeDeepCopy_Internal(ast, origCasted->ItExpr, true, copiedNodesList)); + + break; + } + case AST_IfStmt: { TreeNodeDeepCopy_Start(IfStmt); diff --git a/source/common/scripting/frontend/zcc_parser.h b/source/common/scripting/frontend/zcc_parser.h index c9c1a2933..d0b6264da 100644 --- a/source/common/scripting/frontend/zcc_parser.h +++ b/source/common/scripting/frontend/zcc_parser.h @@ -145,6 +145,9 @@ enum EZCCTreeNodeType AST_MixinDef, AST_MixinStmt, AST_ArrayIterationStmt, + AST_TwoArgIterationStmt, + AST_ThreeArgIterationStmt, + AST_TypedIterationStmt, NUM_AST_NODE_TYPES }; @@ -532,6 +535,31 @@ struct ZCC_ArrayIterationStmt : ZCC_Statement ZCC_Statement* LoopStatement; }; +struct ZCC_TwoArgIterationStmt : ZCC_Statement +{ + ZCC_VarName* ItKey; + ZCC_VarName* ItValue; + ZCC_Expression* ItMap; + ZCC_Statement* LoopStatement; +}; + +struct ZCC_ThreeArgIterationStmt : ZCC_Statement +{ + ZCC_VarName* ItVar; + ZCC_VarName* ItPos; + ZCC_VarName* ItFlags; + ZCC_Expression* ItBlock; + ZCC_Statement* LoopStatement; +}; + +struct ZCC_TypedIterationStmt : ZCC_Statement +{ + ZCC_VarName* ItType; + ZCC_VarName* ItVar; + ZCC_Expression* ItExpr; + ZCC_Statement* LoopStatement; +}; + struct ZCC_IfStmt : ZCC_Statement { ZCC_Expression *Condition; diff --git a/source/common/scripting/vm/vm.h b/source/common/scripting/vm/vm.h index 73c4b48bb..2b7344d5d 100644 --- a/source/common/scripting/vm/vm.h +++ b/source/common/scripting/vm/vm.h @@ -724,6 +724,11 @@ struct AFuncDesc extern FieldDesc const *const VMField_##cls##_##scriptname##_HookPtr; \ MSVC_FSEG FieldDesc const *const VMField_##cls##_##scriptname##_HookPtr GCC_FSEG = &VMField_##cls##_##scriptname; +#define DEFINE_FIELD_NAMED_UNSIZED(cls, name, scriptname) \ + static const FieldDesc VMField_##cls##_##scriptname = { #cls, #scriptname, (unsigned)myoffsetof(cls, name), ~0u, 0 }; \ + extern FieldDesc const *const VMField_##cls##_##scriptname##_HookPtr; \ + MSVC_FSEG FieldDesc const *const VMField_##cls##_##scriptname##_HookPtr GCC_FSEG = &VMField_##cls##_##scriptname; + #define DEFINE_FIELD_BIT(cls, name, scriptname, bitval) \ static const FieldDesc VMField_##cls##_##scriptname = { #cls, #scriptname, (unsigned)myoffsetof(cls, name), (unsigned)sizeof(cls::name), bitval }; \ extern FieldDesc const *const VMField_##cls##_##scriptname##_HookPtr; \ @@ -792,6 +797,7 @@ class AActor; class PFunction; VMFunction *FindVMFunction(PClass *cls, const char *name); +VMFunction* FindVMFunction(const char* name); #define DECLARE_VMFUNC(cls, name) static VMFunction *name; if (name == nullptr) name = FindVMFunction(RUNTIME_CLASS(cls), #name); FString FStringFormat(VM_ARGS, int offset = 0); diff --git a/source/common/scripting/vm/vmframe.cpp b/source/common/scripting/vm/vmframe.cpp index a13829dda..635bace63 100644 --- a/source/common/scripting/vm/vmframe.cpp +++ b/source/common/scripting/vm/vmframe.cpp @@ -54,8 +54,14 @@ CUSTOM_CVAR(Bool, vm_jit, true, CVAR_NOINITCALL) Printf("You must restart " GAMENAME " for this change to take effect.\n"); Printf("This cvar is currently not saved. You must specify it on the command line."); } +CUSTOM_CVAR(Bool, vm_jit_aot, true, CVAR_NOINITCALL) +{ + Printf("You must restart " GAMENAME " for this change to take effect.\n"); + Printf("This cvar is currently not saved. You must specify it on the command line."); +} #else CVAR(Bool, vm_jit, false, CVAR_NOINITCALL|CVAR_NOSET) +CVAR(Bool, vm_jit_aot, false, CVAR_NOINITCALL|CVAR_NOSET) FString JitCaptureStackTrace(int framesToSkip, bool includeNativeFrames, int maxFrames) { return FString(); } void JitRelease() {} #endif @@ -282,6 +288,25 @@ static bool CanJit(VMScriptFunction *func) return false; } +void VMScriptFunction::JitCompile() +{ + if(!(VarFlags & VARF_Abstract)) + { + #ifdef HAVE_VM_JIT + if (vm_jit && CanJit(this)) + { + ScriptCall = ::JitCompile(this); + if (!ScriptCall) + ScriptCall = VMExec; + } + else + #endif // HAVE_VM_JIT + { + ScriptCall = VMExec; + } + } +} + int VMScriptFunction::FirstScriptCall(VMFunction *func, VMValue *params, int numparams, VMReturn *ret, int numret) { // [Player701] Check that we aren't trying to call an abstract function. @@ -291,18 +316,8 @@ int VMScriptFunction::FirstScriptCall(VMFunction *func, VMValue *params, int num { ThrowAbortException(X_OTHER, "attempt to call abstract function %s.", func->PrintableName); } -#ifdef HAVE_VM_JIT - if (vm_jit && CanJit(static_cast(func))) - { - func->ScriptCall = JitCompile(static_cast(func)); - if (!func->ScriptCall) - func->ScriptCall = VMExec; - } - else -#endif // HAVE_VM_JIT - { - func->ScriptCall = VMExec; - } + + static_cast(func)->JitCompile(); return func->ScriptCall(func, params, numparams, ret, numret); } diff --git a/source/common/scripting/vm/vmintern.h b/source/common/scripting/vm/vmintern.h index 9a3e2d401..44fb53463 100644 --- a/source/common/scripting/vm/vmintern.h +++ b/source/common/scripting/vm/vmintern.h @@ -481,4 +481,6 @@ public: private: static int FirstScriptCall(VMFunction *func, VMValue *params, int numparams, VMReturn *ret, int numret); + void JitCompile(); + friend class FFunctionBuildList; }; diff --git a/source/common/textures/formats/anmtexture.cpp b/source/common/textures/formats/anmtexture.cpp index 5024edca2..dbc51bae5 100644 --- a/source/common/textures/formats/anmtexture.cpp +++ b/source/common/textures/formats/anmtexture.cpp @@ -72,9 +72,10 @@ FImageSource *AnmImage_TryCreate(FileReader & file, int lumpnum) if (memcmp(check, "LPF ", 4)) return nullptr; file.Seek(0, FileReader::SeekSet); auto buffer = file.ReadPadded(1); + if (buffer.size() < 4) return nullptr; std::unique_ptr anim = std::make_unique(); // note that this struct is very large and should not go onto the stack! - if (ANIM_LoadAnim(anim.get(), buffer.data(), buffer.size() - 1) < 0) + if (ANIM_LoadAnim(anim.get(), buffer.bytes(), buffer.size() - 1) < 0) { return nullptr; } diff --git a/source/common/textures/formats/pcxtexture.cpp b/source/common/textures/formats/pcxtexture.cpp index 494adeb1f..6981f91e0 100644 --- a/source/common/textures/formats/pcxtexture.cpp +++ b/source/common/textures/formats/pcxtexture.cpp @@ -161,7 +161,7 @@ void FPCXTexture::ReadPCX1bit (uint8_t *dst, FileReader & lump, PCXHeader *hdr) uint8_t rle_value = 0; auto srcp = lump.Read(lump.GetLength() - sizeof(PCXHeader)); - uint8_t * src = srcp.data(); + const uint8_t * src = srcp.bytes(); for (y = 0; y < Height; ++y) { @@ -211,7 +211,7 @@ void FPCXTexture::ReadPCX4bits (uint8_t *dst, FileReader & lump, PCXHeader *hdr) TArray colorIndex(Width, true); auto srcp = lump.Read(lump.GetLength() - sizeof(PCXHeader)); - uint8_t * src = srcp.data(); + const uint8_t * src = srcp.bytes(); for (y = 0; y < Height; ++y) { @@ -265,7 +265,7 @@ void FPCXTexture::ReadPCX8bits (uint8_t *dst, FileReader & lump, PCXHeader *hdr) int y, bytes; auto srcp = lump.Read(lump.GetLength() - sizeof(PCXHeader)); - uint8_t * src = srcp.data(); + const uint8_t * src = srcp.bytes(); for (y = 0; y < Height; ++y) { @@ -306,7 +306,7 @@ void FPCXTexture::ReadPCX24bits (uint8_t *dst, FileReader & lump, PCXHeader *hdr int bytes; auto srcp = lump.Read(lump.GetLength() - sizeof(PCXHeader)); - uint8_t * src = srcp.data(); + const uint8_t * src = srcp.bytes(); for (y = 0; y < Height; ++y) { diff --git a/source/common/textures/formats/webptexture.cpp b/source/common/textures/formats/webptexture.cpp index 4a3233c9e..e86ed4a11 100644 --- a/source/common/textures/formats/webptexture.cpp +++ b/source/common/textures/formats/webptexture.cpp @@ -65,9 +65,9 @@ FImageSource *WebPImage_TryCreate(FileReader &file, int lumpnum) file.Seek(0, FileReader::SeekSet); auto bytes = file.Read(); - if (WebPGetInfo(bytes.data(), bytes.size(), &width, &height)) + if (WebPGetInfo(bytes.bytes(), bytes.size(), &width, &height)) { - WebPData data{ bytes.data(), bytes.size() }; + WebPData data{ bytes.bytes(), bytes.size() }; WebPData chunk_data; auto mux = WebPMuxCreate(&data, 0); if (mux) diff --git a/source/common/textures/textureid.h b/source/common/textures/textureid.h index c441cb9d5..5237acdae 100644 --- a/source/common/textures/textureid.h +++ b/source/common/textures/textureid.h @@ -1,5 +1,7 @@ #pragma once +#include + enum class ETextureType : uint8_t { Any, @@ -28,6 +30,7 @@ class FTextureID public: FTextureID() = default; + FTextureID(std::nullptr_t) : texnum(0) {} bool isNull() const { return texnum == 0; } bool isValid() const { return texnum > 0; } bool Exists() const { return texnum >= 0; } diff --git a/source/common/utility/tarray.h b/source/common/utility/tarray.h index e60772688..b0ab192cc 100644 --- a/source/common/utility/tarray.h +++ b/source/common/utility/tarray.h @@ -657,6 +657,44 @@ public: std::swap(Most, other.Most); } + // aliases with STL compliant names to allow using TArrays with templates designed for STL containers + + size_t size() const + { + return Count; + } + + T* data() const + { + return Data(); + } + + T& front() const + { + return *Data(); + } + + T& back() const + { + return Last(); + } + + void resize(size_t i) + { + Resize(i); + } + + void push_back(T& elem) + { + Push(elem); + } + + void clear() + { + Clear(); + } + + private: T *Array; unsigned int Count; diff --git a/source/core/codegen_raze.cpp b/source/core/codegen_raze.cpp index cd0fbf862..4cb88dfc8 100644 --- a/source/core/codegen_raze.cpp +++ b/source/core/codegen_raze.cpp @@ -519,3 +519,19 @@ void SetRazeCompileEnvironment() compileEnvironment.CheckSpecialMember = CheckForMemberDefault; compileEnvironment.CheckCustomGlobalFunctions = ResolveGlobalCustomFunction; } + +// todo: clean up this mess +extern bool HasGameSpecificTwoArgForEachLoopTypeNames() { return false; } +extern const char* GetGameSpecificTwoArgForEachLoopTypeNames() { return ""; } +extern bool IsGameSpecificTwoArgForEachLoop(FxTwoArgForEachLoop*) { return false; } +extern FxExpression* ResolveGameSpecificTwoArgForEachLoop(FxTwoArgForEachLoop*) { return nullptr; } +extern bool HasGameSpecificThreeArgForEachLoopTypeNames() { return false; } +extern const char* GetGameSpecificThreeArgForEachLoopTypeNames() { return ""; } +extern bool IsGameSpecificThreeArgForEachLoop(FxThreeArgForEachLoop*) { return false; } +extern FxExpression* ResolveGameSpecificThreeArgForEachLoop(FxThreeArgForEachLoop*) { return nullptr; } +extern bool HasGameSpecificTypedForEachLoopTypeNames() { return false; } +extern const char* GetGameSpecificTypedForEachLoopTypeNames() { return ""; } +extern bool IsGameSpecificTypedForEachLoop(FxTypedForEachLoop*) { return false; } +extern FxExpression* ResolveGameSpecificTypedForEachLoop(FxTypedForEachLoop*) { return nullptr; } +extern bool IsGameSpecificForEachLoop(FxForEachLoop*) { return false; } +extern FxExpression* ResolveGameSpecificForEachLoop(FxForEachLoop*) { return nullptr; } diff --git a/source/core/initfs.cpp b/source/core/initfs.cpp index a250ffe6b..15d52da0e 100644 --- a/source/core/initfs.cpp +++ b/source/core/initfs.cpp @@ -47,6 +47,7 @@ #include "findfile.h" #include "palutil.h" #include "startupinfo.h" +#include "files.h" using namespace FileSys; @@ -153,6 +154,7 @@ static std::vector ParseGameInfo(std::vector& pwads, c static std::vector CheckGameInfo(std::vector& pwads) { +#if 1 // scan the list of WADs backwards to find the last one that contains a GAMEINFO lump for (int i = (int)pwads.size() - 1; i >= 0; i--) { @@ -180,18 +182,18 @@ static std::vector CheckGameInfo(std::vector& pwads) else resfile = FResourceFile::OpenDirectory(filename); - FName gameinfo = "GAMEINFO.TXT"; - if (resfile != NULL) + const char* gameinfo = "GAMEINFO.TXT"; + if (resfile != nullptr) { - uint32_t cnt = resfile->LumpCount(); + uint32_t cnt = resfile->EntryCount(); for (int c = cnt - 1; c >= 0; c--) { - FResourceLump* lmp = resfile->GetLump(c); - - if (FName(lmp->getName(), true) == gameinfo) + if (!stricmp(resfile->getName(c), gameinfo)) { // Found one! - auto bases = ParseGameInfo(pwads, resfile->FileName, (const char*)lmp->Lock(), lmp->LumpSize); + auto data = resfile->Read(c); + auto wadname = resfile->GetFileName(); + auto bases = ParseGameInfo(pwads, wadname, data.string(), (int)data.size()); delete resfile; return bases; } @@ -199,6 +201,7 @@ static std::vector CheckGameInfo(std::vector& pwads) delete resfile; } } +#endif return std::vector(); } @@ -445,8 +448,8 @@ void InitFileSystem(TArray& groups) FILE* f = fopen("filesystem.dir", "wb"); for (int num = 0; num < fileSystem.GetNumEntries(); num++) { - auto fd = fileSystem.GetFileAt(num); - fprintf(f, "%.50s %60s %d\n", fd->getName(), fileSystem.GetResourceFileFullName(fileSystem.GetFileContainer(num)), fd->Size()); + auto fd = fileSystem.FileLength(num); + fprintf(f, "%.50s %60s %d\n", fileSystem.GetFileFullName(num), fileSystem.GetResourceFileFullName(fileSystem.GetFileContainer(num)), fd); } fclose(f); } diff --git a/source/core/maphack.cpp b/source/core/maphack.cpp index 7b00914f0..9b91c3623 100644 --- a/source/core/maphack.cpp +++ b/source/core/maphack.cpp @@ -320,7 +320,7 @@ CCMD(md4sum) { auto data = fr.Read(); uint8_t digest[16]; - md4once(data.data(), (uint32_t)data.size(), digest); + md4once(data.bytes(), (uint32_t)data.size(), digest); for (int j = 0; j < 16; ++j) { Printf("%02x", digest[j]); diff --git a/source/core/maploader.cpp b/source/core/maploader.cpp index 653b6970c..9c6a4e5e7 100644 --- a/source/core/maploader.cpp +++ b/source/core/maploader.cpp @@ -547,7 +547,7 @@ void loadMap(const char* filename, int flags, DVector3* pos, int16_t* ang, secto fr.Seek(0, FileReader::SeekSet); auto buffer = fr.Read(); uint8_t md4[16]; - md4once(buffer.data(), (unsigned)buffer.size(), md4); + md4once(buffer.bytes(), (unsigned)buffer.size(), md4); PostProcessLevel(md4, filename, sprites); loadMapHack(filename, md4, sprites); setWallSectors(); @@ -589,7 +589,7 @@ static void Decrypt(void* to_, const void* from_, int len, int key) // //========================================================================== -static void P_LoadBloodMapWalls(uint8_t* data, size_t len, TArray& lwalls) +static void P_LoadBloodMapWalls(const uint8_t* data, size_t len, TArray& lwalls) { uint8_t infoBlock[37]; int mapver = data[5]; @@ -698,7 +698,7 @@ TArray loadMapWalls(const char* filename) if (isBlood()) { auto data = fr.Read(); - P_LoadBloodMapWalls(data.data(), data.size(), lwalls); + P_LoadBloodMapWalls(data.bytes(), data.size(), lwalls); return lwalls; } diff --git a/source/core/menu/loadsavemenu.cpp b/source/core/menu/loadsavemenu.cpp index e5e32986e..a16822794 100644 --- a/source/core/menu/loadsavemenu.cpp +++ b/source/core/menu/loadsavemenu.cpp @@ -71,14 +71,14 @@ void FSavegameManager::ReadSaveStrings() FResourceFile *savegame = FResourceFile::OpenResourceFile(entry.FilePath.c_str(), true); if (savegame != nullptr) { - FResourceLump *info = savegame->FindLump("info.json"); - if (info == nullptr) + auto info = savegame->FindEntry("info.json"); + if (info < 0) { // savegame info not found. This is not a savegame so leave it alone. delete savegame; continue; } - auto fr = info->NewReader(); + auto fr = savegame->GetEntryReader(info, true); FString title; int check = G_ValidateSavegame(fr, &title, true); fr.Close(); diff --git a/source/core/palette.cpp b/source/core/palette.cpp index 8512faf0f..8d444571b 100644 --- a/source/core/palette.cpp +++ b/source/core/palette.cpp @@ -125,7 +125,7 @@ void paletteLoadFromDisk(void) unsigned length = numshades * 256; auto buffer = fil.Read(length); if (buffer.size() != length) return; - lookups.setTable(0, buffer.data()); + lookups.setTable(0, buffer.bytes()); paletteloaded |= PALETTE_SHADE | PALETTE_TRANSLUC; } diff --git a/source/core/raze_sound.cpp b/source/core/raze_sound.cpp index 4af1311b9..0ec4c4166 100644 --- a/source/core/raze_sound.cpp +++ b/source/core/raze_sound.cpp @@ -89,10 +89,13 @@ void S_SetReverb(int strength) // //========================================================================== -std::vector RazeSoundEngine::ReadSound(int lumpnum) +TArray RazeSoundEngine::ReadSound(int lumpnum) { auto wlump = fileSystem.OpenFileReader(lumpnum); - return wlump.Read(); + TArray buffer(wlump.GetLength(), true); + auto len = wlump.Read(buffer.data(), buffer.size()); + buffer.Resize(len); + return buffer; } //========================================================================== diff --git a/source/core/raze_sound.h b/source/core/raze_sound.h index 8e465a04f..bccf5a0e8 100644 --- a/source/core/raze_sound.h +++ b/source/core/raze_sound.h @@ -47,5 +47,5 @@ public: virtual bool SourceIsActor(FSoundChan* chan) { return chan->SourceType == SOURCE_Actor; } virtual int SoundSourceIndex(FSoundChan* chan) { return 0; } virtual void SetSource(FSoundChan* chan, int index) {} - std::vector ReadSound(int lumpnum) override; + TArray ReadSound(int lumpnum) override; }; diff --git a/source/core/savegamehelp.cpp b/source/core/savegamehelp.cpp index bdf37ad26..8c80a4da5 100644 --- a/source/core/savegamehelp.cpp +++ b/source/core/savegamehelp.cpp @@ -136,13 +136,13 @@ bool ReadSavegame(const char* name) if (savereader != nullptr) { - auto lump = savereader->FindLump("info.json"); - if (!lump) + auto lump = savereader->FindEntry("info.json"); + if (lump < 0) { delete savereader; return false; } - auto file = lump->NewReader(); + auto file = savereader->GetEntryReader(lump); if (G_ValidateSavegame(file, nullptr, false) <= 0) { delete savereader; @@ -150,18 +150,17 @@ bool ReadSavegame(const char* name) } file.Close(); - auto info = savereader->FindLump("session.json"); - if (info == nullptr) + auto info = savereader->FindEntry("session.json"); + if (info < 0) { delete savereader; return false; } - void* data = info->Lock(); + auto data = savereader->Read(info); FRazeSerializer arc; - if (!arc.OpenReader((const char*)data, info->LumpSize)) + if (!arc.OpenReader(data.string(), data.size())) { - info->Unlock(); delete savereader; return false; } @@ -171,7 +170,6 @@ bool ReadSavegame(const char* name) SerializeSession(arc); g_nextskill = gi->GetCurrentSkill(); arc.Close(); - info->Unlock(); delete savereader; // this can only be done after the load is complete @@ -247,7 +245,7 @@ bool WriteSavegame(const char* filename, const char *name) M_FinishPNG(&savepic); auto picdata = savepic.GetBuffer(); - FileSys::FCompressedBuffer bufpng = { picdata->Size(), picdata->Size(), FileSys::METHOD_STORED, 0, static_cast(crc32(0, &(*picdata)[0], picdata->Size())), (char*)&(*picdata)[0] }; + FileSys::FCompressedBuffer bufpng = { picdata->size(), picdata->size(), FileSys::METHOD_STORED, 0, static_cast(crc32(0, &(*picdata)[0], picdata->size())), (char*)&(*picdata)[0] }; TArray savegame_content; TArray savegame_filenames; diff --git a/source/core/searchpaths.cpp b/source/core/searchpaths.cpp index e8963e54e..a46e9c626 100644 --- a/source/core/searchpaths.cpp +++ b/source/core/searchpaths.cpp @@ -628,10 +628,10 @@ TArray ParseAllGrpInfos(TArray& filelist) engine_res.reset(FResourceFile::OpenResourceFile(baseres, true)); if (engine_res) { - auto basegrp = engine_res->FindLump("engine/grpinfo.txt"); - if (basegrp) + auto basegrp = engine_res->FindEntry("engine/grpinfo.txt"); + if (basegrp >= 0) { - auto fr = basegrp->NewReader(); + auto fr = engine_res->GetEntryReader(basegrp, true); if (fr.isOpen()) { groups = ParseGrpInfo("engine/grpinfo.txt", fr, CRCMap); @@ -787,7 +787,7 @@ TArray GrpScan() bool ok = true; for (auto &lump : grp->mustcontain) { - if (!resf->FindLump(lump.GetChars())) + if (resf->FindEntry(lump.GetChars()) < 0) { ok = false; break; diff --git a/source/core/states.cpp b/source/core/states.cpp index b4f16da49..fed9b51e5 100644 --- a/source/core/states.cpp +++ b/source/core/states.cpp @@ -560,7 +560,7 @@ FStateLabels *FStateDefinitions::CreateStateLabelList(TArray & sta // //=========================================================================== -void FStateDefinitions::InstallStates(PClassActor *info, AActor *defaults) +void FStateDefinitions::InstallStates(PClassActor *info, DCoreActor *defaults) { if (defaults == nullptr) { diff --git a/source/core/states.h b/source/core/states.h index f7bb4ba92..318cc9307 100644 --- a/source/core/states.h +++ b/source/core/states.h @@ -39,6 +39,7 @@ #include "dobject.h" +class DCoreActor; struct Baggage; class FScanner; struct FActorInfo; @@ -238,7 +239,7 @@ public: void SetStateLabel(const char *statename, FState *state, uint8_t defflags = SDF_STATE); void AddStateLabel(const char *statename); int GetStateLabelIndex (FName statename); - void InstallStates(PClassActor *info, AActor *defaults); + void InstallStates(PClassActor *info, DCoreActor *defaults); int FinishStates(PClassActor *actor); void MakeStateDefines(const PClassActor *cls); diff --git a/source/games/blood/src/db.cpp b/source/games/blood/src/db.cpp index 293567110..a517fe106 100644 --- a/source/games/blood/src/db.cpp +++ b/source/games/blood/src/db.cpp @@ -613,11 +613,11 @@ void dbLoadMap(const char* pPath, DVector3& pos, short* pAngle, sectortype** cur fr.Seek(0, FileReader::SeekSet); auto buffer = fr.Read(); uint8_t md4[16]; - md4once(buffer.data(), (unsigned)buffer.size(), md4); + md4once(buffer.bytes(), (unsigned)buffer.size(), md4); PostProcessLevel(md4, mapname, sprites); loadMapHack(mapname.GetChars(), md4, sprites); - if (CalcCRC32(buffer.data(), (unsigned)buffer.size() - 4) != nCRC) + if (CalcCRC32(buffer.bytes(), (unsigned)buffer.size() - 4) != nCRC) { I_Error("%s: Map File does not match CRC", mapname.GetChars()); } diff --git a/source/games/exhumed/src/movie.cpp b/source/games/exhumed/src/movie.cpp index 3f08d12a5..7e25ae7e3 100644 --- a/source/games/exhumed/src/movie.cpp +++ b/source/games/exhumed/src/movie.cpp @@ -144,7 +144,7 @@ public: auto wbuffer = audio.samples + audio.nWrite * kSampleSize; for (int i = 0; i < 2205; i++) { - wbuffer[i] = (buffer[i] - 128) << 8; + wbuffer[i] = (buffer.bytes()[i] - 128) << 8; } audio.nWrite++; if (audio.nWrite >= numAudioBlocks) audio.nWrite = 0; diff --git a/source/games/sw/src/scrip2.cpp b/source/games/sw/src/scrip2.cpp index 37fce6a2f..61089d893 100644 --- a/source/games/sw/src/scrip2.cpp +++ b/source/games/sw/src/scrip2.cpp @@ -67,26 +67,25 @@ static bool tokenready; // only true if UnGetToken was ju ============== */ -std::vector LoadScriptFile(const char *filename) +TArray LoadScriptFile(const char *filename) { + TArray ret; FileReader fp; if (!(fp = fileSystem.OpenFileReader(filename)).isOpen()) { // If there's no script file, forget it. - return std::vector(); + return ret; } - auto scriptbuffer = fp.Read(); - - if (scriptbuffer.size() != 0) + ret.Resize(fp.GetLength() + 1); + if (fp.Read(ret.Data(), fp.GetLength()) < fp.GetLength()) { - scriptbuffer.push_back(0); scriptline = 1; endofscript = false; tokenready = false; } - return scriptbuffer; + return ret; }