Skip to content

Commit

Permalink
feat(vmtpp): add VMT library
Browse files Browse the repository at this point in the history
  • Loading branch information
craftablescience committed Jul 25, 2024
1 parent 953d912 commit b0bb376
Show file tree
Hide file tree
Showing 10 changed files with 1,020 additions and 1 deletion.
5 changes: 5 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ option(SOURCEPP_USE_KVPP "Build kvpp library"
option(SOURCEPP_USE_MDLPP "Build mdlpp library" ON)
option(SOURCEPP_USE_STEAMPP "Build steampp library" ON)
option(SOURCEPP_USE_VICEPP "Build vicepp library" ON)
option(SOURCEPP_USE_VMTPP "Build vmtpp library" ON)
option(SOURCEPP_USE_VPKPP "Build vpkpp library" ON)
option(SOURCEPP_USE_VTFPP "Build vtfpp library" ON)
option(SOURCEPP_BUILD_C_WRAPPERS "Build C wrappers for supported libraries" ON)
Expand All @@ -32,6 +33,9 @@ option(SOURCEPP_USE_STATIC_MSVC_RUNTIME "Link to static MSVC runtime library"
if(SOURCEPP_USE_STEAMPP)
set(SOURCEPP_USE_KVPP ON CACHE INTERNAL "")
endif()
if(SOURCEPP_USE_VMTPP)
set(SOURCEPP_USE_KVPP ON CACHE INTERNAL "")
endif()
if(SOURCEPP_USE_VPKPP)
set(SOURCEPP_USE_BSPPP ON CACHE INTERNAL "")
set(SOURCEPP_USE_KVPP ON CACHE INTERNAL "")
Expand Down Expand Up @@ -92,6 +96,7 @@ add_sourcepp_library(kvpp)
add_sourcepp_library(mdlpp)
add_sourcepp_library(steampp C)
add_sourcepp_library(vicepp C CSHARP)
add_sourcepp_library(vmtpp)
add_sourcepp_library(vpkpp C CSHARP NO_TEST)
add_sourcepp_library(vtfpp)

Expand Down
13 changes: 12 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,17 @@ Several modern C++20 libraries for sanely parsing Valve formats, rolled into one
<td align="center">✅</td>
<td align="center">C<br>C#</td>
</tr>
<tr>
<td><code>vmtpp</code></td>
<td>
<ul>
<li><a href="https://developer.valvesoftware.com/wiki/VMT">VMT</a></li>
</ul>
</td>
<td align="center">✅</td>
<td align="center">❌</td>
<td align="center"></td>
</tr>
<tr>
<td><code>vpkpp</code></td>
<td>
Expand Down Expand Up @@ -135,7 +146,7 @@ Several modern C++20 libraries for sanely parsing Valve formats, rolled into one
</tr>
</table>

(\*) Many text-based formats in Source are close to (if not identical to) KeyValues v1, such as [VDF](https://developer.valvesoftware.com/wiki/VDF), [VMT](https://developer.valvesoftware.com/wiki/VMT), and [VMF](https://developer.valvesoftware.com/wiki/VMF_(Valve_Map_Format)).
(\*) Many text-based formats in Source are close to (if not identical to) KeyValues v1, such as [RES](https://developer.valvesoftware.com/wiki/Resource_list_(Source)), [VDF](https://developer.valvesoftware.com/wiki/VDF), and [VMF](https://developer.valvesoftware.com/wiki/VMF_(Valve_Map_Format)).

(&dagger;) The MDL parser is not complete. It is usable in its current state, but it does not currently parse more complex components like animations. This parser is still in development.

Expand Down
97 changes: 97 additions & 0 deletions include/vmtpp/EntityAccess.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
#pragma once

#include <sourcepp/math/Vector.h>

namespace vmtpp {

/// Expose an interface to read values from the entity the VMT is attached to for material proxies.
class IEntityAccess {
public:
virtual ~IEntityAccess() = default;

/// "The number of seconds the current map has been running on the server for."
[[nodiscard]] virtual uint64_t getCurrentTime() const = 0;

[[nodiscard]] virtual float getRenderAlpha() const = 0;

[[nodiscard]] virtual float getAnimationProgress() const = 0;

/// "The distance in units between the current player and the origin of the entity that the material is applied to."
[[nodiscard]] virtual float getDistanceToCurrentPlayer() const = 0;

[[nodiscard]] virtual int getCurrentPlayerTeam() const = 0;

[[nodiscard]] virtual int getTeam() const = 0;

/// "The dot product of the current player's view angle and the relative origin of the material's entity."
[[nodiscard]] virtual float getCurrentPlayerViewDotProduct() const = 0;

[[nodiscard]] virtual float getCurrentPlayerSpeed() const = 0;

[[nodiscard]] virtual sourcepp::math::Vec3f getCurrentPlayerPosition() const = 0;

[[nodiscard]] virtual float getSpeed() const = 0;

[[nodiscard]] virtual sourcepp::math::Vec3f getOrigin() const = 0;

/// "A static random number associated with the entity the material is applied to."
[[nodiscard]] virtual float getRandomNumber() const = 0;

[[nodiscard]] virtual float getHealth() const = 0;

[[nodiscard]] virtual bool isNPC() const = 0;

[[nodiscard]] virtual bool isViewModel() const = 0;

[[nodiscard]] virtual sourcepp::math::Vec3f getWorldDimensionsMinimum() const = 0;

[[nodiscard]] virtual sourcepp::math::Vec3f getWorldDimensionsMaximum() const = 0;

[[nodiscard]] virtual sourcepp::math::Vec3f getCurrentPlayerCrosshairColor() const = 0;
};

class EntityAccessEmpty : public IEntityAccess {
public:
EntityAccessEmpty();

[[nodiscard]] uint64_t getCurrentTime() const override;

[[nodiscard]] float getRenderAlpha() const override;

[[nodiscard]] float getAnimationProgress() const override;

[[nodiscard]] float getDistanceToCurrentPlayer() const override;

[[nodiscard]] int getCurrentPlayerTeam() const override;

[[nodiscard]] int getTeam() const override;

[[nodiscard]] float getCurrentPlayerViewDotProduct() const override;

[[nodiscard]] float getCurrentPlayerSpeed() const override;

[[nodiscard]] sourcepp::math::Vec3f getCurrentPlayerPosition() const override;

[[nodiscard]] float getSpeed() const override;

[[nodiscard]] sourcepp::math::Vec3f getOrigin() const override;

[[nodiscard]] float getRandomNumber() const override;

[[nodiscard]] float getHealth() const override;

[[nodiscard]] bool isNPC() const override;

[[nodiscard]] bool isViewModel() const override;

[[nodiscard]] sourcepp::math::Vec3f getWorldDimensionsMinimum() const override;

[[nodiscard]] sourcepp::math::Vec3f getWorldDimensionsMaximum() const override;

[[nodiscard]] sourcepp::math::Vec3f getCurrentPlayerCrosshairColor() const override;

private:
float random;
};

} // namespace vmtpp
35 changes: 35 additions & 0 deletions include/vmtpp/Proxy.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#pragma once

#include <string>
#include <unordered_map>

namespace vmtpp {

class IEntityAccess;

namespace Proxy {

// We're going to try to implement proxies in a way that's distinct from but still roughly
// comparable to the SDK, so it's easy to compare functionality and get a nice reference!

struct Data {
std::string name;
std::unordered_map<std::string, std::string> variables;
};

using Function = void(*)(Data&, std::unordered_map<std::string, std::string>&, const IEntityAccess&);

Function add(const std::string& name, Function proxy);

Function get(const std::string& name);

void exec(Data& data, std::unordered_map<std::string, std::string>& vmtVariables, const IEntityAccess& entity);

void remove(const std::string& name);

} // namespace Proxy

} // namespace vmtpp

#define VMTPP_MATERIAL_PROXY(name, proxy) \
vmtpp::Proxy::Function VMTPP_MATERIAL_PROXY_##name = vmtpp::Proxy::add(#name, proxy)
71 changes: 71 additions & 0 deletions include/vmtpp/vmtpp.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
#pragma once

#include <initializer_list>
#include <string>
#include <string_view>
#include <unordered_map>
#include <vector>

#include "EntityAccess.h"
#include "Proxy.h"

namespace vmtpp {

namespace Value {

enum class Type {
INT,
FLOAT,
VEC3,
COLOR,
};

[[nodiscard]] Type getProbableType(std::string_view value);

[[nodiscard]] Type getProbableTypeBasedOnAssociatedValues(std::string_view value, std::initializer_list<std::string_view> others);

[[nodiscard]] int toInt(std::string_view value);

[[nodiscard]] std::string fromInt(int value);

[[nodiscard]] float toFloat(std::string_view value);

[[nodiscard]] std::string fromFloat(float value);

[[nodiscard]] sourcepp::math::Vec3f toVec3(std::string_view value);

[[nodiscard]] std::string fromVec3(sourcepp::math::Vec3f value);

[[nodiscard]] sourcepp::math::Vec4f toColor(std::string_view value);

[[nodiscard]] std::string fromColor(sourcepp::math::Vec4f value);

} // namespace Value

class VMT {
public:
explicit VMT(std::string_view vmt, const IEntityAccess& entityAccess_ = EntityAccessEmpty{}, int dxLevel = 98, int shaderDetailLevel = 3, std::string_view shaderFallbackSuffix = "DX9");

[[nodiscard]] std::string_view getShader() const;

[[nodiscard]] bool hasCompileFlag(std::string_view flag) const;

[[nodiscard]] const std::vector<std::string>& getCompileFlags() const;

[[nodiscard]] bool hasVariable(std::string_view key) const;

[[nodiscard]] std::string_view getVariable(std::string_view key) const;

[[nodiscard]] std::string_view operator[](std::string_view key) const;

void update();

private:
const IEntityAccess& entityAccess;
std::string shader;
std::vector<std::string> compileFlags;
std::unordered_map<std::string, std::string> variables;
std::vector<Proxy::Data> proxies;
};

} // namespace vmtpp
82 changes: 82 additions & 0 deletions src/vmtpp/EntityAccess.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#include <vmtpp/EntityAccess.h>

#include <chrono>

using namespace vmtpp;

EntityAccessEmpty::EntityAccessEmpty() {
static float randomNumberGeneratorWinkWink = 0.f;
this->random = randomNumberGeneratorWinkWink++;
}

uint64_t EntityAccessEmpty::getCurrentTime() const {
return std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch()).count();
}

float EntityAccessEmpty::getRenderAlpha() const {
return 1.f;
}

float EntityAccessEmpty::getAnimationProgress() const {
return 0.f;
}

float EntityAccessEmpty::getDistanceToCurrentPlayer() const {
return 0.f;
}

int EntityAccessEmpty::getCurrentPlayerTeam() const {
return 0;
}

int EntityAccessEmpty::getTeam() const {
return 0;
}

float EntityAccessEmpty::getCurrentPlayerViewDotProduct() const {
return 0.f;
}

float EntityAccessEmpty::getCurrentPlayerSpeed() const {
return 0.f;
}

sourcepp::math::Vec3f EntityAccessEmpty::getCurrentPlayerPosition() const {
return {};
}

float EntityAccessEmpty::getSpeed() const {
return 0.f;
}

sourcepp::math::Vec3f EntityAccessEmpty::getOrigin() const {
return {};
}

float EntityAccessEmpty::getRandomNumber() const {
return this->random;
}

float EntityAccessEmpty::getHealth() const {
return 0.f;
}

bool EntityAccessEmpty::isNPC() const {
return false;
}

bool EntityAccessEmpty::isViewModel() const {
return false;
}

sourcepp::math::Vec3f EntityAccessEmpty::getWorldDimensionsMinimum() const {
return {};
}

sourcepp::math::Vec3f EntityAccessEmpty::getWorldDimensionsMaximum() const {
return {};
}

sourcepp::math::Vec3f EntityAccessEmpty::getCurrentPlayerCrosshairColor() const {
return {1.f, 1.f, 1.f};
}
Loading

0 comments on commit b0bb376

Please sign in to comment.