Forum posts

Posted 6 days ago2022-01-11 19:17:53 UTC
in Half-Life Updated (custom SDK) Post #346194

Progress update for 11/01/2022

All changes have been merged into Half-Life Updated CMake and the Unified SDK, and all problems preventing compilation on Linux have been resolved.

Shepard has set up Continuous Integration to automatically build the SDK on Windows and Linux. This is currently used only to automatically determine if the SDK successfully builds on both platforms, but in the future it could be used to automatically provide the latest versions of both the client and server libraries on both platforms.

You can see the CI builds in action here: https://github.com/SamVanheer/halflife-unified-sdk/actions

A badge has been added to the readme to show if builds are succeeding or failing.

All pending pull requests have been merged in on all repositories and all issues have either been resolved, transferred to the Unified SDK repository or closed with the sole exception of an issue tracking a problem with the Half-Life Updated game package which i'll be putting up soon.

I've rewritten the scripts used to create those game packages as well as the game install scripts to use PowerShell instead of batch scripts. PoiwerShell syntax is easier to work with, common commands are easier to recognize and use and most importantly it's cross-platform.

These scripts should work on Linux which will make it easier to create Linux versions of game packages and to install content from other games. Unfortunately PowerShell 7 - which is the cross-platform version - isn't available on Windows 7 which is still supported by this SDK so the scripts are required to work in both PowerShell 5.1 (Windows only) and PowerShell 7. This isn't a problem since the scripts don't rely on any features exclusive to either version but some script code is a bit more verbose as a result (mostly Join-Path usages).

To make the scripts easier to work with the boilerplate logic is separate from game-specific parts, this makes it easier to tell which parts require modifying. It's also been redesigned to support copying content from multiple games which the Unified SDK requires.

malortie has been hard at work creating updated models for the Unified SDK. Low definition and high definition versions of each view model for each set of hands (HEV, PCV and guard) will be included to support using all weapons in any mod. Additionally a third person player model ("player.mdl", used to trace attacks directed at players) for Barney has also been created to match the models used in Half-Life and Opposing Force.

Right now i need to test Half-Life Updated, Opposing Force Updated and Blue Shift Updated's singleplayer campaigns to see if anything is broken. Any issues that crop up that didn't already exist will be fixed to ensure that these repositories contain a relatively stable codebase.

Once that's done i'll put together beta packages for each of the 3 repositories. I'd like to run some tests in multiplayer to make sure nothing is broken there (e.g. broken game mode or friendly fire issues) so if anybody's interested we can organize some tests. I'm going to add basic bot support (bots that just stand in place, no AI) to run some tests in isolation but some game modes require more than that.

Only Half-Life and Opposing Force Updated need multiplayer testing since Blue Shift multiplayer is identical to Half-Life (and the game isn't meant to be played in multiplayer), and Opposing Force multiplayer differs mainly in the existence of the Capture The Flag game mode, so ideally multiplayer testing involves first testing Half-Life deathmatch, teamplay and then the Opposing Force versions before testing CTF.

Once this is all done and all issues have been resolved then a full 1.0.0 release will be done for each Updated repository and each repository will then be archived. The Half-Life Updated CMake repository will be removed entirely after this, since it's no longer useful at that point.

This entire process will probably take a week or 2 to complete depending on whether any bugs crop up.

For now i'd like to thank everybody who contributed to the development of these projects and getting the Unified SDK up and running, and i hope to have a first version of the SDK available for use soon, but we'll see about that after this work is all done.
Posted 1 week ago2022-01-09 11:20:29 UTC
in A bit of trouble making the hud purple Post #346190
I doubt the updated SDK is at fault here. Just tell us what you did so we can see what's causing the problem.
Posted 1 week ago2022-01-08 11:53:20 UTC
in A bit of trouble making the hud purple Post #346187
Which changes did you make?
Posted 2 weeks ago2021-12-30 17:16:16 UTC
in game crashes if i shoot a tracer Post #346176
This happens because of a problem in older versions of the STL included with Visual Studio. It was removed at some point: https://github.com/microsoft/STL/issues/717

Make sure you're using Visual Studio 2019 or newer with the v141 toolset or newer, make sure it's not the XP toolset and make sure Visual Studio is up-to-date. Run the Visual Studio Installer and install any updates you get for Visual Studio.

If the problem persists, let me know which version of Windows you're using and which version of Visual Studio you're using (the exact version number, like 16.11.8).
Posted 2 weeks ago2021-12-29 22:46:12 UTC
in game crashes if i shoot a tracer Post #346173
i use an older version of halflife-updated because the solution won't compile on vs2019 and it constantly errors on some std::atomic thingy
What is the error you're getting related to std::atomic?
Posted 2 weeks ago2021-12-29 11:48:47 UTC
in game crashes if i shoot a tracer Post #346171
What is the error you're getting?
Posted 3 weeks ago2021-12-25 19:26:20 UTC
in Half-Life Updated (custom SDK) Post #346160

Progress update

The VS 2017 project files have been removed from all repositories.

I've fixed a few more bugs that slipped in during some of the overhauls. One of the biggest is a change to the Vector type that changed how the GCC compiler optimized passing vectors by value. This change broke compatibility with the particle manager library, which ships as part of the game.

To fix the issue i've re-implemented the library in the client library. I've also fixed a couple bugs in it, such as memory leaks and a use-after-free issue. Because it's now implemented in the client it is no longer possible for players to cheat by deleting the particleman library.

All changes have been merged into the following repositories:
  • Half-Life: Opposing Force Updated
  • Half-Life: Blue Shift Updated
  • Condition Zero Deleted Scenes SDK
The Deleted Scenes SDK also received an implementation of the material system used by that game. Nothing is actually using the material system, but the implementation is now available for use if anybody wants it. It's unlikely that it will work without further modifications. I plan to implement a new material system in the Unified SDK at some point that will provide this functionality in a better way.

This system was partially implemented already (i needed parts of it for something years back), so i've finished it to get the work out of the way.

I've also fixed a mistake i made in the DS SDK where CTriggerChangeKeyValue didn't increment a variable used to keep track of how many keyvalues had been initialized already.

The DS SDK will be archived along with the others when the Unified SDK is set to become the new default SDK for use.

I forgot about the halflife-fog repository, which will also be integrated into the Unified SDK. It implements OpenGL-based fog effects. Deleted Scenes also has fog so whichever implementation of those two and any alternates provided by the community is best will be used.

Most of the changes made to Half-Life Updated have been merged into Half-Life Updated CMake. A few changes remain, then i can focus on merging the changes into the Unified SDK.

I'd also like to thank suXinjke, vasiavasiavasia95, malortie and Shepard for helping to get everything ready.

Discord channel

The TWHL server channel #sharplife has been renamed to #unified-sdk. It serves as a channel to discuss anything related to Half-Life Updated, Half-Life Unified SDK and Half-Life Asset Manager.

Status of SharpLife

Several people have asked about SharpLife, what its status is.

This project is on indefinite hold since its scope is much, much bigger than anything else i'm working on right now.

Whereas these SDKs are about improving game code, re-implementing some engine functionality and improving the quality of the code, SharpLife is about making a whole new engine. Such an endeavor is much more difficult and requires more time and experience to accomplish.

At this time i'd like to focus on improving these SDKs and finishing Half-Life Asset Manager. Perhaps after that i might work on SharpLife again, or attempt a C++-based version of the concept, but that's not something i'd like to decide right now. It's likely that this won't even be possible for several years given the amount of work that's left to be done for current projects.

The goal behind using C# was to make it easier to use for modders with little (C++) programming experience, but if an Angelscript-based scripting system can be used to handle game code (entities et al) then this isn't really necessary. The performance-critical parts can be implemented in C++ and the rest in Angelscript, or C# if such a combination is feasible.

The two languages are fairly similar to one another so it will likely come down to how easy they are to use in such a situation. That's not to say that i've done any research on the feasibility of using either, it's nothing more than an idea at this time. Perhaps with the right abstractions the language used can be swapped out much like Source's scripting system supports multiple implementations, but that would require a fair amount of work either way.

I'd advise against getting hyped up for any of this stuff since it's years away from even starting development, assuming such a thing will ever be done at all.

Immediate future of Unified SDK

As i said in the previous post, once work on the now-obsolete repositories is done the Unified SDK will get some cleanup work done. There are a lot of things i'd like to do but i don't want to make any promises before i know what's actually possible (both technically and legally). There is a list of planned upgrades on the repository you can check to see what's going to be done sooner or later: https://github.com/SamVanheer/halflife-unified-sdk/projects/3

Most planned upgrades concern improving boilerplate code that involve supporting multiple games within a single codebase. The goal is to allow you to play any Half-Life 1 PC game's campaign through the Unified SDK without having to make code changes. To make this work, some features like global model replacement are needed. Those features in turn need models to support this, namely viewmodels for each game's hand models. I haven't had time to check for the existence of such models though i have seen some used.

If anybody knows of viewmodels for the Opposing Force-exclusive weapons that use HEV and security guard hands, that would be a big help. Ideally both low definition and high definition versions should be used for consistency with the HD models setting, but i'll take what i can get.

It's important to remember that such models must be available under a license that allows redistribution with mods. This is to avoid scenarios where mods based on the Unified SDK suddenly need to remove files due to a copyright claim.

Right now i need to do a lot of merging of code into the Unified SDK, so it'll be some time before everything is synchronized. Once it's done i'll make another post to announce the archiving of all obsolete repositories. All remaining open issues will be moved to the Unified SDK repository at that time.

That should be just about everything for now.
Posted 3 weeks ago2021-12-24 23:29:07 UTC
in [help] Rendering a model fullbright Post #346159
That flag only works in Sven Co-op. It's not implemented in vanilla Half-Life.
Posted 3 weeks ago2021-12-22 12:53:23 UTC
in Custom character model not showing up in game Post #346152
You need to change the code for the entity to change the model. Most entities in Half-Life don't support custom models, so the model listed in the fgd will only show up in the map editor.
Posted 1 month ago2021-12-04 20:33:23 UTC
in Half-Life Updated (custom SDK) Post #346105
The project changes have been discussed in a few places the past few days, you can see some of these discussions here:
https://knockout.chat/thread/30908/1#post-1091521 (next page has the replies)

More discussions also took place on the TWHL and Half-Life Creations Discord servers.

The feedback has universally shown that nobody uses the VS 2017 projects anymore, so i'm going to remove those from all repositories.

Once the Unified SDK has been released i'm going to archive Half-Life Updated, Half-Life Opposing Force: Updated, Half-Life: Blue Shift Updated and Half-Life Updated CMake.

Projects made using these repositories will still work as before and will still be able to pull all changes made. Archiving a repository makes it read-only and adds a banner informing visitors that's it's been archived. No new issues or pull requests can be made and you will no longer be able comment on anything.

The Unified SDK provides all of the functionality that these projects have all in one SDK with a better workflow. It also solves some common tasks like changing HUD colors (easily done programmatically and through map entities, and will also be possible through configuration files and scripting) and integrating Opposing Force weapons and NPCs so there is no reason to continue using the other projects.

It does require knowledge of CMake but that's not a terribly difficult thing to learn. The project uses modern CMake so it's not an overly complicated thing to learn and use, and most of the time you're only going to be adding new headers and source files which is trivially easy to do.

Existing Github issues will be transferred to the Unified SDK repository to continue work on them there.

The first order of business now is merging all changes into the other repositories and fixing any issues that crop up. Once that's done i can get the Unified SDK to a releasable state. A final release of all of the Updated projects will be done to ensure that changes made to configuration files are available for use, and then the repositories will be archived and will direct users to the Unified SDK repository instead through the description. Further development will be done with that repository the same way it's been done before.

After that's all done i'd like to merge as many of the improvements i made to Enhanced Half-Life into this project as well, as well as the improved weapon class management from the better weapons repository (which will also be archived and eventually removed). I'm also going to review the changes i made to HLEnhanced to see what i can merge from that.

I'm also going to look at integrating an improved version of Condition Zero: Deleted Scenes' trigger_sequence entity. If Angelscript by itself is not good enough to manage such scripting functionality then providing a means of doing so through both entity and scripting means would be useful. It is likely that scripting will be sufficient given how the entity is implemented: https://github.com/SamVanheer/czeror-sdk/blob/1e732141e5823fa69596de388a269c1ba34a33b7/dlls/CTriggerSequence.cpp#L270-L371

This will allow the archiving of the Deleted Scenes SDK which only contains this entity and nothing else from Deleted Scenes. A full Deleted Scenes SDK would take a fair bit of work and i'm not so sure about making that. I'd prefer to add it to the Unified SDK instead as an optional component to make it easier to work with, but that's something i'm going to wait to decide on until after work on Half-Life campaign support is complete.

All in all, this will see the merging of these projects into a single project:
  • Half-Life Updated
  • Half-Life: Opposing Force Updated
  • Half-Life: Blue Shift Updated
  • Half-Life Updated CMake
  • HLEnhanced
  • Enhanced Half-Life
  • Half-Life Better Weapons
  • Condition Zero: Deleted Scenes SDK
After this point the goal will be to continue fixing compiler warnings, enabling and fixing clang-tidy warnings, cleaning up code, fixing bugs and improving SDK functionality.

I would like to ask that all contributors hold off on making more pull requests for now until i can get this all sorted out. I'm not certain how long it will take to complete the remaining work, but hopefully it should be done in a few weeks time at the most.

I've made the Half-Life Unified SDK repository visible. If needed pull requests can be made on that repository instead.

Note that this is a work in progress project, i haven't yet had the chance to review the requirements for a clean git clone and CMake setup. While everything should work fine there may be problems i'm not aware of right now. Once the work on the to-be-archived repositories is complete i can focus on finishing the first release of this project.

That's all for now, i'd like to thank everybody that gave feedback and to those contributing to development. Hopefully we can get a first version of the Unified SDK released before the end of the year. I'm very interested to hear what people have to say about it.
Posted 1 month ago2021-12-01 16:53:01 UTC
in Half-Life Updated (custom SDK) Post #346091
I've got a question for anybody using Half-Life Updated: does anybody still use the Visual Studio 2017 project files?

The system requirements for Visual Studio 2019 are almost identical to that of 2017, mainly differing in the minimum version of Windows 10 required and the recommended amount of RAM:
https://docs.microsoft.com/en-us/visualstudio/releases/2017/vs2017-system-requirements-vs
https://docs.microsoft.com/en-us/visualstudio/releases/2019/system-requirements

VS 2019 is also more flexible in how much disk space is required due to its different approach to installing it, but that's about it.

If nobody has need for it then i'll remove the 2017 project files. This will simplify development a bit and allows certain newer features to be used (like C++20).

The VS 2019 project files should work out of the box with VS 2022 (it will upgrade the files on first open), so there is no need to maintain a separate set of files for now.

In the long run once the Half-Life Unified SDK has been released it might be easier to use that as a base instead since it will encompass Half-Life Updated, Half-Life Opposing Force: Updated and Half-Life: Blue Shift Updated. At that point i'd prefer to archive the older repositories to focus on developing that version of the SDK instead.

It uses CMake so there is no problem with supporting different versions of Visual Studio, although this does require users to learn to use CMake. I can cover the basics in a tutorial which should get people going, but it does add an additional barrier to new modders.

On the flip side it does automate things that have to be done manually, like setting up the copying of game libraries to the mod directory so there are benefits to using it.

On that note: to use the CMake version of Half-Life Updated you currently have to build the INSTALL target to deploy the libraries, which might be a bit cumbersome and annoying. Visual Studio won't build this target if you try to run a project that needs to be rebuilt and instead launches an older version.

I can change this to instead deploy them when building the projects themselves, if this is something that's considered preferable i'll make it do that.

Some people have asked to make certain new features in the Unified SDK optional, like Angelscript for example. I've been pondering how feasible this is and i think i can make it work, although certain features that depend on such features will not work as well if it's disabled (e.g. conditional cfg files wouldn't work).

I'd like to get people's opinions on the matter before i make any decisions.
Posted 1 month ago2021-12-01 16:37:28 UTC
in problems with porting my mod to steam Post #346090
Don't use the change game dialog, that's obsolete and not guaranteed to work properly. The correct way to launch mods under Steam is to launch it directly through Steam or launching Half-Life with the -game parameter.

If your mod isn't loading then there might be a problem with your client.dll file. Follow this tutorial to figure out what's wrong: https://twhl.info/wiki/page/Half-Life_Programming_-_Debugging#h6017c5e17e73f
Posted 1 month ago2021-11-29 12:58:16 UTC
in Half-Life Updated (custom SDK) Post #346081
Regarding the work being done on Half-Life Updated at the moment: i'd like to thank malortie for helping to clean things up and fix bugs, it's really helping to make the SDK better.

I've completely eliminated the use of Windows headers in game code now, only 2 files still use it: inputw32.cpp (for raw input and mouse threading, which i'd like to convert to std::thread and related types) and interface.cpp (for loading dlls at runtime).

This has cut down on compile time some more. I've also reworked a ton of code to properly convert between bool and other types which should make it easier to tell when something's a true/false value or not.

I've switched the C++ language version from C++14 to C++17 which provides some useful additions like inline global variables.

I've enabled clang-tidy as part of the code analysis feature in Visual Studio, so you'll get more warnings now. A fair number of warnings are being shown because of the SDK's tendency to include headers only in source files so there are false positives, i'm going to try to fix those as much as i can.

Clang-tidy is configured through a configuration file in the root of the repository, i'm going to systematically enable more of those as i work through the remaining warnings.

I've also added a clang-format configuration file to the root of the repository which Visual Studio uses to format files. This ensures that formatting files is done consistently rather than depending on individual developers' text editor settings, but i'm still working out the kinks in the settings. The issue for this change provides more information on how it works, and how to mass-format all files: https://github.com/SamVanheer/halflife-updated/issues/84

I've been doing lots of code cleanup as well, removing duplicate forward declarations, using inline to avoid the need to declare globals as extern separately and otherwise improving the quality of the code.

The long-term goal is to have 0 warnings at the highest warning settings with as many clang-tidy warnings enabled as possible to enforce stricter and more correct code.

Note that due to recent changes existing save games will not work with newer updated builds. If you update your fork to include these changes, or if you use the next pre-built libraries you'll need to delete the save games to prevent problems from cropping up.
Posted 1 month ago2021-11-29 12:45:42 UTC
in Half-Life Updated (custom SDK) Post #346080
In regards to scripting, and assuming scripting allows for creating custom monsters and entities, I believe this could definitely be a plus.
Yeah that's certainly a possibility. I implemented custom entity/NPC/weapon support in Sven Co-op using Angelscript before.

I worked out some of the details for a scripting system last week. Since this is derived from Sven Co-op's scripting system (aka "previous system") i'll be comparing it to that. Note that this is all conceptual, i haven't written any code for this yet so it could change if it's not feasible.

Plugins and map scripts are virtually identical, unlike the previous system (somebody should update that page though, custom entities have been allowed in plugins for a long time now). The only difference is how long scripts stay loaded for.
Plugins normally get loaded on server startup and stay loaded until the server shuts down, unless the scripts are explicitly unloaded or reloaded.

Map scripts are loaded when a map references them, and are unloaded if the next map does not reference it. Some option to keep a script loaded regardless by extending its lifetime is required so you can have for example a script that runs in the background of every map, like a stat tracker or something.

The simplest way to do this is to use the configuration file system to list a script for use in multiple maps, or every map by listing it in the server config file. Then it'd just be a plugin loaded as a map script, with the option to conditionally include it using the Condition key.

One of the problems that popped up was that multiple scripts would be written to be the main script, with initialization code in the automatically called functions MapInit, MapActivate, MapStart and PluginInit. So if you then included multiple scripts those functions would conflict with each-other.

To solve this problem each script listed in the config file, and each script referenced by trigger_script would be loaded into its own Angelscript module. A module is basically a C++ library in terms of scope, so these API functions wouldn't conflict unless you mark them as shared.

In the previous system shared entities weren't allowed because it could interfere with the reloading of plugins. If you have a script that defines something as shared, include it in 2 or more plugins, change the shared code and then reload one of the plugins it'll fail to load because the shared code is now different.

I'd flip this behavior on its head now. Allow shared stuff, even between plugins and map scripts, but disallow making API functions shared to prevent one script from monopolizing them.

This approach makes it much easier to design things like AFB, which is a plugin manager written in Angelscript. To work around the lack of shared entities you have to add your script to a function to initialize the system: https://github.com/Zode/AFBase/blob/acd7ba7e1248538d9b660638915dc91a7da59deb/scripts/plugins/AFBaseExpansions.as

With shared entities each plugin can be its own module, referencing a shared Plugin class. Plugins then need only register their plugin class, which the plugin manager can query from the shared code to manage each plugin instance.

Such registration can be automated to this point:
AFBRegister register(@MyAFBPluginClass());
The AFBRegister class registers the plugin in its constructor and unregisters it in its destructor, thus tying the plugin lifetime to that of its containing module. You won't even need to write a PluginInit function anymore. AFBRegister would be a shared class.

The API functions should also be improved, there are too many of them. Each module should get exactly 2 of them: an init and shutdown function. Everything else should be event-driven:
void ScriptInit()
{
    //Called when the script is first loaded.
    //Subscribe to the MapInit event. All events define a unique event type associated with it, even if they don't have any data or methods.
    Events.GetEvent<MapInitEvent>().Subscribe(@MapInit);
}

void ScriptShutdown()
{
    //Called when the script is about to be discarded/unloaded.
    //Don't need to manually free event handlers because they'll be removed automatically, but it can be done manually like this.
    Events.RemoveAllEventHandlersFromCallingModule();
}

//All event handlers follow the same structure: void return type, one parameter taking the event by handle.
void MapInit(MapInitEvent@ event)
{
    //Called when the map is starting for any reason, map scripts could be in the process of being loaded right now, so inter-module communication isn't advised at this time.

    //Equivalent to Source's logic_auto outputs: https://developer.valvesoftware.com/wiki/Logic_auto
    switch (event.InitType)
    {
    case MapInitType::NewGame:
        //The map is being loaded for the first time, like when the map or changelevel console commands are used.
        break;
    case MapInitType::LoadGame:
        //The map is being loaded from a save game, which means the player is loading a save game or a map is being returned to through a trigger_changelevel.
        break;
    case MapInitType::NewRound:
        //For game modes that use round-based gameplay, a new round is starting.
        break;

    //More types if needed.
    }
}
The event system replaces hooks and allows for compile-time compatibility checking of events. The previous system had to rely on variable parameters because hooks could have any number of parameters, so you could technically pass in an integer into a function that's expecting a function handle. You'd get an error at runtime, so it's not as obvious that you've made a mistake.

On the C++ side you'd publish events like this:
Events.GetEvent<MapInitEvent>().Publish(MapInitType::NewGame);
This would then internally create the event object:
//Curiously Recurring Template Pattern-based base class
template<typename TEvent>
class Event
{
public:
    //Reference counting code omitted for brevity.

    template<typename... Args>
    void Publish(Args&&... args)
    {
        //Event is created with reference count 1, ownership transferred to smart pointer.
        //Event constructor is invoked with template parameters.
        as::SmartPtr event{new TEvent{std::forward<Args>(args)...}};

        //Event handlers are tracked by the Events global and will invoke all handlers.
        Events.PublishEvent(event.Get());

        //Smart pointer releases event, usually destroys it if no script holds on to it.
    }
};

class EventSystem
{
public:
    template<typename TEvent>
    void PublishEvent(TEvent* event)
    {
        //Probably a std::unordered_map<std::reference_wrapper<type_info>, as::SmartPtr<asITypeInfo>>.
        asITypeInfo* type = GetScriptTypeFromCppType<TEvent>();

        if (!type)
        {
            return;
        }

        auto context = ...;

        //Finds or creates the list of handlers for this event type.
        const std::vector<as::SmartPtr<asIScriptFunction>>& handlers = GetEventHandlersForType(type);

        for (const auto& function : handlers)
        {
            //Context setup and error handling omitted for brevity.
            context->SetArgObject(0, event);
            context->Execute();
        }
    }
};
Custom entities require a fair bit of work to support. You need to expose the class you want custom entities to inherit from, expose the API to call base class implementations (e.g. calling CBaseMonster::Killed from your NPC's Killed method) and you need to write a wrapper that forwards calls to the script for any virtual functions it has.

The C++ side also needs to support custom entity creation by implementing the custom function. I haven't quite figured out how to save and load them since the save game system doesn't use custom. I could hack it by saving custom entities to have the custom class, and then saving the actual classname separately. That solves the problem, but there is still the issue of scripts changing the custom entity implementation.

One map could have a script A.as that defines a custom entity foo, and the next map could have a script B.as that also defines a custom entity foo. When such an entity is transitioned between maps its composition can change dramatically, including changing base classes.

Custom weapons could be restored as an NPC for example, and the pointer to the weapon would now be invalid since CBasePlayerWeapon* isn't compatible with CBaseMonster*. There are no safeguards in the save game system against this and it would take some doing to support it, so the initial version of the scripting system wouldn't be able to support it.

Custom entity support thus needs to be disabled in singleplayer with an error message in the console if you try to register them anyway (since saving the game and loading it would make it disappear).

I'll work this out more once i've completed work on the first version of the unified SDK. There's still a lot of work left to be done in all of the existing repositories to clean things up.
Posted 2 months ago2021-11-14 18:52:17 UTC
in Half-Life Updated (custom SDK) Post #346059
I've been working to add a few new systems to the Unified SDK to make modding easier to do through configuration files instead of relying on hard-coded settings so much.

Here are most of them in action:
User posted image
These are all of the systems i've added, though some are not entirely finished:

String pool

This replaces the engine's ALLOC_STRING engine function, and changes behavior to allocate memory once per string, so calling it multiple times with the same string doesn't allocate more memory. Very efficient, this change also frees up a little memory in the engine's available memory pool.

It also no longer performs escape character parsing which required game_text to be changed to perform this parsing by itself. This behavior was inconsistent and could cause difficult to debug problems otherwise.

Better support for writing code that works on both client and server

The server's engine functions interface now has better support on the client which makes it easier to write code that works on both sides.

This also includes helper functions like Con_Printf which will unconditionally print to the console, and supports all of printf's format options (the engine's version is limited to C89 printf options).

Access to the engine's filesystem

The engine has a filesystem interface used to load files from game and mod directories. I've provided access to it, as well as a couple helper functions to easily load files without the risk of leaking memory.

You can use this to load files from the mod directory only if needed, for example server configuration files should never load from other directories to prevent custom and downloaded content from overriding it. Conversely you can also load files from all of those directories if needed, such as map configuration files.

Support for creating console variables and commands using unified syntax on client and server

The server requires you to create cvars whereas the client has the engine create them for you; i've created an abstraction that does this for you. This abstraction also prepends an sv_ or cl_ prefix automatically so you can have the same variables and commands on both sides.

You can set variables created this way using the new command line syntax :command_name command_value or :(sv_|cl_)command_name command_value.
If specified without the prefix it will apply to both the server and client versions. This also works properly for server variables which the engine will not initialize from the command line if you launch a listen server manually through the main menu.

Command functions can also be object methods by using a lambda to wrap it:
g_ConCommands.CreateCommand("my_command", [this](const auto& args) { MyCommandHandler(args); });

void MyClass::MyCommandHandler(const CCommandArgs& args)
{
    Con_Printf("%d arguments:\n", args.Count());

    for (int i = 0; i < args.Count(); ++i)
    {
        Con_Printf("d\n", args.Argument(i)));
    }
}
CCommandArgs is a thin wrapper around engine functions that makes it easier to work with commands by indicating which functions are available in all libraries.

Improved logging

I've added the spdlog library and set up the functionality to create loggers for subsystems. This allows you to log output with more control over how much is visible and what kind of output it is. As you can see in the screenshot above you can easily distinguish which system is logging something, and what kind of information it is.

This system loads settings from a configuration file. You can specify default logger settings so you can enable more debug output for all loggers, or even disable them all. You can also configure each logger individually.

There are console commands to list all of the loggers that exist, as well as to manually change the log level at runtime.

Angelscript-based scripting functionality

Bare bones Angelscript support has been added. The creation of script engines, contexts and modules is provided with error reporting for failure, as well as engine message logging, exception logging and proper handling for C++ exceptions including problematic behavior regarding longjmp (essentially C's version of exceptions), which could put the game engine or the script engine in an invalid state otherwise (note that longjmp does not seem to be caught by catch-all statements in VS2019, this used to happen in VS2012 but fail-safe logic should prevent the problem from occurring).

There is currently no scripting support for plugins and map scripts, but it's something i'd like to add if there's interest.

JSON-based configuration files

I've added support for loading JSON configuration files and parsing them. Error handling is done for you so if there's invalid JSON it'll be reported automatically.

I've also added JSON Schema-based extended error reporting for debugging purposes. This provides additional information when needed to indicate which part of the given JSON is invalid. It's only enabled with a debug cvar since it adds a lot of overhead.

Here's an example of the errors it will log (given an array instead of an object):
[startup] [error] Error validating JSON "/Defaults" with value "[{"LogLevel":"trace"}]": unexpected instance type
The JSON schemas can also be written to a file and used as input to tools that can generate JSON editors. This makes it easier to edit JSON and shows what kind of options you have.

I've also allowed the use of comments in JSON. This is a non-standard extension to the format, but is supported in most JSON libraries and the benefits are too good to ignore.

Game configuration files

Building on JSON support, there is a system for loading game configuration files. These are files that contain configuration data that needs to be applied every time a new map is loaded. This replaces server.cfg, listenserver.cfg and map change cfg files, which are mostly handled by the engine.

Additionally maps can have a config file as well. A file called cfg/maps/<mapname>.json will be loaded if the map with that name is started.

Here's an example of such a file used to configure the server for a new map:
{
    "Includes": [
        "cfg/shared.json"
    ],
    "Sections": [
        {
            "Name": "Echo",
            "Message": "Hello World!"
        },
        {
            //Commands to configure multiplayer server
            "Name": "Commands",
            "Condition": "Multiplayer",
            "Commands": [
                "echo Hello World from command!",
                // disable autoaim
                "sv_aim 0",
                // player bounding boxes (collisions, not clipping)
                "sv_clienttrace 3.5",
                // disable clients' ability to pause the server
                "pausable 0",
                // maximum client movement speed
                "sv_maxspeed 270",
                // load ban files"
                "exec listip.cfg",
                "exec banned.cfg"
            ]
        }
    ]
}
The Includes value is a list of files to include before the current one, and makes sharing settings between servers and maps very easy. You could for instance make a map series where each map includes a file that contains the shared configuration before changing some for specific maps.

Here are the contents of the included file:
{
    "Sections": [
        {
            "Name": "Echo",
            "Message": "Hello World from shared.json!"
        }
    ]
}
The Sections value is a list of section objects that apply to the game. Each section can have a condition associated with it evaluated at load time to determine whether the section should be used or not.

This condition is evaluated using Angelscript by wrapping it in a function:
bool Evaluate()
{
    return condition;
}
To prevent abuse this evaluation will time out after 1 second, so the server won't lock up due to some clever infinite loop trick.

There are currently only two conditions to check: Singleplayer and Multiplayer. I plan to expand on this with gamemode detection (deathmatch, coop, teamplay, etc) as well as checking the map name and the value of cvars.

The Echo section simply prints the message to the console, useful for debugging to see if your file is getting loaded properly.

The Commands section provides the same functionality as the cfg files this system replaces. It lets you provide a list of console commands to execute.
For security purposes map config files are checked against a whitelist to limit the commands that can be executed. This prevents maps from doing things like changing the RCON password or the listen server host's name.

This whitelist is loaded from another JSON file:
[
    "sv_gravity"
]
So server operators can manage this whitelist themselves if needed.

Though the configuration files for servers, maps and map changes are currently identical they are actually defined separately. Some will get sections exclusive to one or two of them in which case trying to use them in a format that doesn't have them will cause an error to be logged the console, but otherwise it will continue loading the file.
With this stuff implemented i can get to work implementing skill.json functionality and its map-specific equivalent. There are also a few changes needed to support things like Xen aliens fighting with Race X aliens (they're treated as allies by the game's code). Black ops have the same problem when it comes to fighting human military types (also allies).

I've also been updating the other SDKs to include bug fixes and improvements. There are some mistakes i made in Opposing Force that should be merged into any other projects that use that code.

There isn't much more work to do before a first release can happen. Since this is a lot of work i'll be doing an alpha release first to get some feedback, then at least one beta before a full release can be done.

That's all for now, feedback and suggestions are always welcome.
Posted 2 months ago2021-10-21 12:49:45 UTC
in Half-Life Updated (custom SDK) Post #345987
Yeah but they haven't been active for a while.
Posted 3 months ago2021-10-13 16:43:08 UTC
in Half-Life Updated (custom SDK) Post #345971
I doubt it, many of these changes could break existing content.

Alfred doesn't work at Valve anymore. I don't know if anybody is assigned to handle GoldSource at the moment.
Posted 3 months ago2021-10-12 18:58:27 UTC
in Half-Life Updated (custom SDK) Post #345968
I've been working on the Half-Life Unified SDK for a bit now. I've completed Blue Shift integration including refactoring of code and i've added all of the Opposing Force code as well, though no refactoring has been done there.

To support multiple games in a single codebase i've added two new features: custom hud colors and a flashlight/nightvision toggle.

Both of them can be controlled through code to set a default of your choosing, and hud colors can be changed using a new entity.
There are also cheat commands to set the values to a desired setting for testing purposes.

Crosshairs now also respect the hud color setting. The red autoaim variant is now drawn separately on top of the normal crosshair, and i've updated the crosshair sprites to remove the duplicate pixels. No more having to edit those sprites if your mod has a different hud color.

As a consequence of this change the autoaim crosshair for Opposing Force weapons is now its normal crosshair plus 2 red dots to the sides. I think this looks better than the original crosshair which reused the 357 autoaim crosshair. It still reuses the 357 crosshair now, but only the red dots.

To implement this functionality crosshair drawing has been moved from the engine to the client dll. This includes changing the crosshair position if sv_aim is turned on.

Unfortunately scaling up the crosshair isn't quite as easy because the standard sprite drawing functions don't support that, and the triangle API will crash if used in Software mode. It also causes the crosshair to appear blurry.

Scaling up the sprites themselves is probably the best way to deal with that.

Here's a video:
Next up is Opposing Force refactoring, which mostly involves undoing the copy pasting of code and using inheritance instead. Then i'll be adding JSON-based configuration files to handle some other features required to let you play through the three campaigns without code changes or swapping files.

Edit: further testing shows that scaled crosshairs are possible, but only in OpenGL. Software mode has issues drawing things on-screen.
Thanks to vasiavasiavasia95 for pointing this out.
Posted 3 months ago2021-09-30 11:31:31 UTC
in Half-Life Updated (custom SDK) Post #345963
Half-Life Updated, Opposing Force Updated, Blue Shift Updated and Half-Life Updated CMake betas released:

Notable changes for all projects:
  • Reverted "Fixed multisource having off-by-one error in trigger handling" (halflife issue #1737) to avoid edge cases where entities triggering the multisource use a delayed trigger which is not supported by fixed code
  • Fixed underwater breathing sounds playing when standing in shallow water (halflife issue #3110)
  • Multiple fixes for Linux makefiles to ensure all projects compile, link and run properly
  • Moved DMC and Ricochet projects to their own repositories so changes made to Half-Life games don't break those projects
Full changelog: https://github.com/SamVanheer/halflife-updated/wiki/Changelog#changes-in-v100-beta-006

Notable changes for Half-Life Updated CMake:
  • Made the client link with the VGUI and SDL2 libraries using relative paths to avoid hard-coding developer's paths in the client library (matches the vanilla SDK's behavior)
  • Updated setup instructions to remove Windows XP support and use VS 2019 as the example
  • Removed unused files (source code, libraries, makefiles)
  • Removed obsolete code (CBaseSpectator, cine_ entities, cycler_prdroid)
  • Restructured source code directories to make things easier to find
  • Added Mac support to the CMake files (untested)
  • Enabled multi-processor compilation when using Visual Studio (roughly 2-3 times faster compilation)
  • Removed the HALFLIFE_DIRECTORY CMake variable, the Half-Life directory is now auto-detected from the CMAKE_INSTALL_PREFIX variable which you have to set to your mod directory (see setup instructions on the wiki)
  • Added CMake settings to set up debugging command line arguments more easily when launching from Visual Studio (enabling console, cheats and developer mode on startup, passing additional command line arguments such as +map)
  • If the HalfLife_HLDS_DIRECTORY variable is set to the Half-Life Dedicated Server directory the contents of your mod's cl_dlls and dlls directories will be copied to the HLDS copy of your mod when building the INSTALL target allowing easier debugging of dedicated servers
Full changelog: https://github.com/SamVanheer/halflife-updated-cmake/wiki/Changelog#changes-in-v100-beta-001

Downloads: (The CMake version differs meaningfully only in how modders create mod libraries so there is no separate download)

This should conclude preparation work for the Half-Life Unified SDK which will combine Half-Life Updated CMake with Opposing Force Updated and Blue Shift Updated.
Posted 4 months ago2021-09-05 12:13:30 UTC
in Half-Life Asset Manager Post #345922
Half-Life Model Viewer 2.11 has been released: https://github.com/SamVanheer/HL_Tools/releases/tag/HLMV-V2.11

This update is aimed at fixing Windows XP support. It is recommended that you use Asset Manager if your system supports it.

Changes:
  • Removed unnecessary filesystem path canonicalization (broken on Windows XP)
  • Disabled "correct sequence group filenames" feature on Windows XP (does not work due to non-functional filesystem support)
  • Disabled depth writing instead of clearing depth buffer bit so the OpenGL window isn't black in Textures mode
  • Recompiled HLMV using Visual Studio 2017 to ensure the program works on Windows XP
  • Bundled the latest Visual C++ redistributable (16.7) that works properly on Windows XP so users can run the program properly
Note for Windows XP users: do not install Visual C++ redistributables newer than version 16.7 (file version 14.27.29114.0). Newer redistributables will install a runtime that does not work on Windows XP and will break programs that rely on it. If you have one installed it is recommended to uninstall it.
Posted 4 months ago2021-09-03 17:35:40 UTC
in Half-Life Updated (custom SDK) Post #345919
That project is GPL-licensed which makes it incompatible with any Half-Life SDK-based projects since it requires the engine's source code to be made available. This also means that that project in itself is a license violation since the author has not made the engine's source code available either. I think they intended to use LGPL, but that's up to them to figure out.

That aside, bunny hopping is limited by player physics code. Adding a switch to conditionally disable it is possible but that's something that i think should be left up to individual mod authors. It's easy enough to disable the anti-bunny hopping check (comment out this function call), making it conditionally disabled can be done by using one of the player user variables to network a setting (compressing it down to one bit can save some space in case you need the other user variables).

The spectator mode is something i haven't really looked at, what's wrong with it exactly? I can fix it without having to reference anybody else's code provided i know what's wrong. You can enter spectator mode by setting allow_spectators to 1 and using the spectate command to enter spectator mode, but perhaps there are some problems with it.
Are you using the right model viewer? You're making a Source model so only Source model viewer can open it, usually the one in the bin directory of whichever game you're making it for.
Posted 4 months ago2021-08-20 18:14:22 UTC
in Half-Life Asset Manager Post #345889
Half-Life Asset Manager V1.3.0 has been released: https://github.com/Solokiller/HL_Tools/releases/tag/HLAM-V1.3.0
New User InterfaceNew User Interface
This release marks the first major update to the user interface. The existing tab-based panels have been redesigned to be dockable, which allows you to move them around to other sides of the window, put them side by side (assuming there is enough space), and even float them on top of the window. You can also close panels and open them again through the Asset->Panels menu or by right clicking in the tab area of a docked panel.

All dock panels are designed to lay themselves out both horizontally and vertically to minimize their size when docked and floated. Some panels are quite large so docking them may block other panels from being docked if there is not enough space to shift the user interface around.

Several new panels have been added: the Transformation panel works much like Hammer's Transform dialog in that it allows you to rotate, move and scale the model. Rotation is still a bit buggy when models have multiple root bones (e.g. sat_globe.mdl's satellites) but it works well enough otherwise.

Scaling now has options to control which parts of the model to scale, including both data that was previously scaled along with meshes such as hitboxes, as well as data such as the eye position which previously wasn't scaled.

The Scene panel is now where settings affecting only the objects in the 3D scene in Asset Manager reside. Here you can change the position of the object that the model is attached to, as well as control visibility of the ground and background. You can now move the ground object (e.g. move it to -36 on the Z axis to match the feet position of player models).

Note however that mirroring will not work with the ground moved up or down, this is slated to be fixed in HLAM 2.0.0. Both the ground and background will now automatically be made visible if you select a texture. Changing the filename will also try to change the texture in real-time. It is also possible to enable texture tiling for the ground and choose the tiling size, specified in units. The ground texture will automatically shift depending on the current sequence's linear movement (used to control movement speed and direction in-game), allowing you to preview this information.

The Textures panel now behaves differently. Previously opening this tab would automatically switch to a texture view, this is now its own separate window accessible through a separate tab bar next to the drawn polygons count. By default the original synchronized opening behavior is enabled, but this can be disabled. You can now edit textures while viewing the model itself, which dramatically improves visual feedback when making changes to texture flags and color remapping.

For V1.3.0 only the Texture view is rendered using Qt's image rendering API instead of OpenGL, so texture filtering settings will not affect this view. HLAM 2.0.0 will re-implement OpenGL based rendering to return this functionality.

You can now view the Skeleton as defined in the reference mesh provided to the Studiomdl compiler. This is a combo box next to the new view tab bar, to the right of the drawn polygons count. This lets you see how the Skeleton is defined without any animations affecting it. The Sequences panel will be disabled in this pose because none of its settings can affect it. This pose is very useful when using the Transformation panel since changes to the model are applied to the skeleton data and not the animation data.

You can refresh the model at any time by pressing F5 or by using Tools->Refresh. This reloads the model if possible and tries to restore the user interface to match as closely as possible the previous state. It is possible for the model being reloaded to be in an incomplete state if it is being recompiled (Studiomdl writes directly to the file which can be slow enough to cause race conditions). Asset Manager tries to make sure this won't load the model by trying to obtain an exclusive lock on the file but there may be cases where this can still happen.

Several memory leaks have been fixed, the object that the model is attached to used to be leaked and GPU texture memory was being leaked when the model is refreshed. Application shutdown now frees more memory to help avoid leaking state.

The OpenGL version check has been changed to be non-fatal, and checks for OpenGL 2.1 now instead of 3.0. Most program features should work for users running with OpenGL 2.1, except for texture mipmaps which relies on a 3.0 feature.

HLAM 2.0.0 is slated to get an upgrade to all of the OpenGL code to use shaders instead of immediate mode. This will improve performance and make future graphical features easier to implement and maintain. Additionally the GLEW dependency will be removed (since it only works with desktop OpenGL) and (assuming it works) Google's ANGLE will be used to provide support for users with OpenGL versions below 2.1. ANGLE provides OpenGL implementations that use DirectX under the hood. Users running on older systems (typically Windows 7 with integrated graphics cards) should be able to use all of Asset Manager's features through ANGLE once it has been upgraded, but this will require testing to verify.

This will ensure anybody running Windows 7 or newer can use Asset Manager.

After 2.0.0 has been finished the next update will include more user interface improvements. It's too early to go into detail on those, but the changes are largely based on user feedback, so if you have any suggestions or improvements i'd love to hear about them!

You can always create an issue on Github, post in the TWHL thread, post in the Knockout thread, or message me on Discord on TWHL's Discord server.
Posted 4 months ago2021-08-18 09:14:49 UTC
in Half-Life Asset Manager Post #345887
They're all in beta. Once V1.3.0 is out i'm going to merge in a pull request that's been sitting on the main updated repo, and fix an issue with the CMake version (an include path on the wrong CMake target, not a big deal but still wrong).

Since EHL ended up being so much bigger than i anticipated i want to merge the three updated repos together to make something that's easier to work with. Mostly cleaning up Gearbox's code for HUD colors and the mass of code duplication in the NPC code. Beyond that EHL has large updates waiting to be completed, there's not much to say about that right now.

I'm planning to get back to work on HLAM after the merge project is done so i can switch it to using OpenGL shaders. I've been trying to fix OpenGL support for old and integrated GPUs, some devices don't support OpenGL 2.1 while being capable of running shaders just fine due to poor driver support, so i've been looking into how to get Qt's ANGLE and software renderers to work. I've found that ANGLE works only with OpenGL 2.0, i'm guessing because it's interpreting the version number as OpenGL ES 2.0 (the embedded version of the API), so once shaders are in place i can try to get that working.

ANGLE will allow users to run the program even without OpenGL 2.1 support because it can use DirectX under the hood and integrated GPUs do support that properly. And the software renderer might work as well but that i haven't tested yet.

Once that's done i can release HLAM 2.0.0, and following that see what's next to be done. V1.3.0 is getting a bit more work right now to hopefully fix a crash on shutdown that some users are experiencing, i've fixed a memory leak that might be related to that. I decided to take care of a bunch of legacy code that was due for refactoring and removal, so things are streamlined a bit more.

That's about it for now really, i just need to take a good look around the codebase for any problems i can find so i can get everything working smoothly.
Posted 5 months ago2021-08-13 19:24:32 UTC
in Half-Life Asset Manager Post #345877
I've created ModDB file entries for both Half-Life Model Viewer 2.10 and Half-Life Asset Manager 1.2.0:
https://www.moddb.com/games/half-life/downloads/half-life-model-viewer-210
https://www.moddb.com/games/half-life/downloads/half-life-asset-manager-1-2-0

V1.3.0 is undergoing final testing and should be ready to release this weekend.
Posted 5 months ago2021-08-07 11:10:37 UTC
in Half-Life Asset Manager Post #345861
Half-Life Asset Manager now has a GameBanana page: https://gamebanana.com/tools/7311
Posted 5 months ago2021-08-05 11:32:38 UTC
in Half-Life Asset Manager Post #345849
I checked to see if i could build HLAM with Qt 5.6 to make a Windows XP compatible build, it's not possible. The new features being used are required to make everything work properly, there is no replacement for some of them.

I did change the OpenGL version setting so if you're using an OpenGL 2.1 GPU you should be able to run the program now if you're on Vista or newer (Vista has a minimum requirement of an OpenGL 2.1 GPU).

Beta 003 is out: https://github.com/Solokiller/HL_Tools/releases/tag/HLAM-V1.3.0-beta003

Bug Fixes
  • Fixed Body Parts panel not showing body, submodel, skin if there are no controllers in model
  • Fixed mirror on axis not always mirroring on the correct axis
  • Fixed cancelling program close with unsaved asset causing crash
UI Changes
  • Changed OpenGL version to 1.0
Project Changes
  • Reworked matrix calculations to be consistent
Microsoft is developing a command line parsing library if you're open to using something non-standard: https://github.com/dotnet/command-line-api

It's in beta but it's pretty good already. I use it for some tools and it works well.
Posted 5 months ago2021-08-01 17:13:45 UTC
in Half-Life Asset Manager Post #345831
Half-Life Asset Manager V1.3.0 Beta 002 has been released: https://github.com/Solokiller/HL_Tools/releases/tag/HLAM-V1.3.0-beta002

Changes:
  • Made OpenGL version check non-fatal, made it into a one off warning instead (It may be possible to run HLAM 1.x with OpenGL 1 only, but this requires testing)
  • Added actions to place camera on positive or negative X/Y/Z axis
  • Added more checkboxes to Scale mode:
    • Separated Scale Meshes into Scale Meshes, Scale Hitboxes and Scale Sequence BBoxes
    • Added Scale Eye Position and Scale Attachments
Posted 5 months ago2021-07-31 11:57:24 UTC
in Half-Life Asset Manager Post #345827
Initialy, my idea was adding an options/choises for placing the camera on the +X -X +Y -Y +Z -Z axises, and the camera to point perfectly perpendicular at the zeroes/crossing of the other two axises, that make a perpendicular plane to the camera axis. The distance betwen the camera and the other two axises can be automated, so the whole model is viewable, no model parts going out of the 3D view planel, or even better, it can be added an option to select that distance by number, or the user sliding along the axis (which means practicaly: zoom in and out), so a user can keep it constant when rotating around the model, which is more convinient if you ask me.
Most of that is already possible. The camera is currently always placed on the +X axis facing back to the model, positioned far enough away to show the entire model, up to a certain maximum size because there are some really large models out there (e.g. Natural Selection has some map-sized models). You can move the camera along the camera forward axis using the scroll wheel or right click+drag. The distance can be set explicitly through the Cameras panel. The Arc Ball camera maintains its distance while rotating around the model.

I can add buttons to place the camera on a specific axis to let you easily change viewpoints. I've added a new issue to track this: https://github.com/Solokiller/HL_Tools/issues/191
But then I realized, that it will be way way better if there is an option for switching between the proposed above and this:
Imagine the model have a perfect geometry center (center of mass). Imagine all 3 axises cross at this center instead of 0. Now if place the camera on any of this new "center of mass axises", the user will see the model better, because the "axises that cross at 0" are usually way way under the model compared to "center of mass axises". Everything else stays the same as above.
This is already the case. The current sequence's bounding box is used to get the center of the model, the camera is positioned at the middle point of that box. The Arc Ball camera rotates around this point. The point doesn't update when you change sequences. Asset->Center View will use the current sequence to re-center the camera so you can use that to get a sequence-specific position.
No. I only suggest, that after placing the camera on an axis as described above, the user can move/rotate/zoom/roam it freely like usually/before from that axes position (go away from that axis). I just mean, that the view/camera shouldn't stay locked on the axis until explicitly other predetermined camera position is selected.
This is the current behavior.
This is just a basic predetermined top, front, right side, etc. scene view in most programs. Goldsource model viewers just only have: start from only one option - center view (front view) and then you "free roam" around the model.
There are 3 camera modes in HLAM, 2 of which were also in HLMV:
  • Arc Ball (called Free View in HLMV) which rotates around the model (around the origin point in HLMV)
  • First Person
  • Free View (HLAM only, works like noclipping in-game in letting you fly freely around the scene)
Aside from that, is Windows XP 32 SP3 build for HLAM even possible?
No, Qt dropped support for XP after Qt 5.6. HLAM uses 5.15 and depends on certain features that were added after 5.6's release. 5.6 isn't available for download through Qt's maintenance tool anymore, though i did find a download link on their website but i don't know if that's a usable build.

Qt 6 drops support for anything older than Windows 10, so support isn't coming back on that end. Microsoft dropped support for XP starting with Visual Studio 2019's toolset, which means if you want to use C++20 you can't support XP. Supporting XP just isn't feasible anymore because of this.
func_train entities teleport to their first target when their Activate() method is called.

Here's a diagram showing how entities work (from Source but applies to GoldSource as well):
User posted image
Creating entities at runtime won't call Activate(), so they won't teleport. You should make a request to the Sven Co-op team to update trigger_createentity to optionally call Activate() so the entity gets set up properly. Or alternatively making entities like these work properly when spawned at runtime without requiring a separate Activate() call.

As a workaround you could try triggering the train to make it teleport, but i can't guarantee that will work.

You could also try using Angelscript to handle the creation of the trains, then you can call Activate() yourself.
Posted 5 months ago2021-07-30 12:34:04 UTC
in Half-Life Asset Manager Post #345819
You can always ask here, on Github or on Discord. Anywhere's fine.

I've added the first suggestion as a feature marked for 2.0.0: https://github.com/Solokiller/HL_Tools/issues/190

For the second one, you want to place the camera on a specific axis facing the model and then be able to switch between any camera mode (aside from first person view) while still having the original camera origin and angles?
Posted 5 months ago2021-07-29 14:32:09 UTC
in Half-Life Asset Manager Post #345812
Half-Life Asset Manager V1.3.0 Beta 001 has been released: https://github.com/Solokiller/HL_Tools/releases/tag/HLAM-V1.3.0-beta001

Notable changes:
  • The user interface has been redesigned to use dock panels. This allows you to move panels around in the tab bar, and more importantly move the panels to other sides of the window, as well as float them. All panels have been optimized to reduce their width and height in horizontal and vertical layout mode. It is possible that some dock panel layout combinations can lead to incorrect window and dock area sizes, this is due to the size of the panels. To fix this resize the window (minimizing and maximizing) or move the panels.
  • All dock panels can be closed and toggled through both the Asset->Panels menu as well as by right clicking in the tab bar region of any docked panels.
  • Added new panel Transformation: this lets you move the model like the old Origin edit widget, scale it like the old Scale Mesh and Scale Bones widgets (now combined with checkboxes to control behavior) and rotate it, though rotation may not always work correctly due to how model data is stored internally
  • Added new panel Scene: this lets you modify the objects that exist in the scene. The buttons to move the model object that used to be part of Model Display have been moved here, along with a new Origin edit widget (this does not modify the actual model data). The ground and background features are now centralized here: the checkboxes to toggle them have been moved here, the texture selection feature is now here as a line edit and updates the texture in real-time, and selecting a texture automatically shows them. The ground origin can now be modified, though this does not work properly when used with Mirror On Ground because mirroring is done using a hack instead of proper mirroring.
  • Added unanimated pose (the skeleton as defined in a modeling program) as reference_mesh sequence
  • The program will now remember which screen it was last opened on and will open on that screen
  • Textures are now drawn on a separate view that can be selected through a tab bar to the right of the FPS and drawn polygons counters. By default selecting the Textures panel will also switch the view to Textures, but this behavior can be disabled in the Options dialog. This allows you to view the 3D model while editing texture properties. Note that textures are no longer drawn using OpenGL, so filtering settings will not affect this view.
This is a beta release intended to gather feedback and to test for bugs.
Posted 5 months ago2021-07-28 08:36:15 UTC
in Half-Life Updated (custom SDK) Post #345809
Thanks!
Posted 5 months ago2021-07-27 12:47:13 UTC
in Half-Life Updated (custom SDK) Post #345807
Thanks! I'm glad you like it.
Posted 5 months ago2021-07-22 20:47:17 UTC
in Half-Life Asset Manager Post #345798
Half-Life Asset Manager V1.2.0 has been released: https://github.com/Solokiller/HL_Tools/releases/tag/HLAM-V1.2.0

Notable changes:
  • Fixed performance issue causing FPS drops
  • Added checks to prevent opening files currently being written to by the studiomdl compiler
  • Added button to flip normals
  • Implemented CTRL+W to close asset feature
  • Implemented F5 to refresh feature
Posted 5 months ago2021-07-19 16:52:00 UTC
in Replacing OpFor night vision with HEV flashlight Post #345788
Posted 6 months ago2021-06-28 09:24:36 UTC
in Need help with weapon coding Post #345709
Take a look at the Gauss gun's code, its secondary attack works a lot like that. It mostly involves handling timing in WeaponIdle.
Posted 7 months ago2021-06-14 09:25:53 UTC
in Specific PAK file loading Post #345701
You can add custom pak files using the IFileSystem interface: https://developer.valvesoftware.com/wiki/IFileSystemV009

However i wouldn't recommend doing this because pak files can't be removed (RemoveSearchPath crashes the game).

The engine can also reset the filesystem at any time if the player changes certain settings which could cause your pak file to be unloaded.
Posted 7 months ago2021-06-12 09:39:16 UTC
in Enhanced Half-Life (custom SDK/mod) Post #345695
Wow, this is some really good work, even for you! The synthetic entities would allow people to make some really cool stuff per-map, I'd imagine... Kind of makes me want to reinstall JACK or Hammer 3.5!
Synthetic entities are just a way to assign a new classname to a set of default keyvalues, really. Scripts with custom entities would be much more powerful than this, but i don't want to add scripting support until the codebase is stable.

On the plus side because i can use code generation i can automate most of the work needed to make custom entities work.

I've been brainstorming on how to design the config file system, and i've come up with some ideas. None of what i'm writing here has been implemented yet.

I've pinned down the definition for template entity configurations some more. I referred to this as "loading default keyvalues from a file" above.
{
  "Name": "TemplateName",
  "Include": [
    {
      "FileName": "some_other_path_under_cfg.json"
    }
  ],
  "KeyValues": [
    {
      "Key": "Key1",
      "Value": "Value1"
    },
    {
      "Key": "Key2",
      "Value": "Value2"
    },
    {
      "Key": "Key1",
      "Value": "Value3"
    }
  ]
}
Included in a map or server configuration file like this:
{
  "EntityTemplates": [
    {
      "FileName": "path_to_template_file.json",
      "Type": "EntityTemplate"
    },
    {
      "FileName": "path_to_other_template_file.json",
      "Type": "DefaultEntityTemplate",
      "EntityNames": [
        "some_entity_name"
      ]
    },
    {
      "FileName": "ammo_9mmclip.json",
      "Type": "SyntheticEntityTemplate",
      "BaseEntityName": "ammo_generic",
      "EntityNames": [
        "ammo_9mmclip",
        "ammo_glockclip"
      ]
    }
  ]
}
A template marked as default will be used to initialize all entities of the types listed in EntityNames. This occurs after entity creation, before any keyvalues are added.

A template marked as synthetic allows mappers to create instances of entities by the given name. Separate synthetic entity configurations are no longer a thing since the syntax is practically identical to templates.

Non-default templates can be referenced by the entity through a keyvalue. The template will be applied after a default template, before any keyvalues are added (possible since we can now access the entity data before keyvalues are handled).

For non-default templates the Type key can be omitted.

So we've got:
  • Synthetic entities: tie a set of default keyvalues to a new entity name
  • Custom entities: define a new entity through script code
  • Default templates: apply default keyvalues to all entities of specific types on creation
  • Entity-specific templates: apply default keyvalues to entities that refer to a template by name
None of this has been implemented yet, it's all proposal-level stuff i'm thinking of so i can design a proper configuration file format and plan for scripting support.

Config files are being designed to be easy to use, i've defined a general-purpose file inclusion syntax that makes it easy to share configurations between maps.

With what i have in mind you could define a hierarchy of default template files to set defaults for every entity, for example default health, model and classification for every monster. This will require code support to make sure mapper-defined settings aren't overwritten. Ideally i could just move the hardcoded values to config files and let the template system do the rest.

If you wanted to make a map pack you'd make a shared config file that includes all of the templates and ties them to their respective entities. You would then have a map-specific config file that includes the shared one:
"Include": [
  {
    "FileName": "some_path_under_cfg.json"
  }
]
Map and server configs can both do the same things, but map configs can have different filters applied to cvar setters and stuff (blacklisting certain cvars):
{
  "Sections": [
    {
      "Name": "Pretty name for debugging",
      "Condition": "Multiplayer && !Deathmatch",
      "InitializationOrder": "PreMapSpawn",
      "Actions": {
        "Cvars": [
          {
            "Name": "mp_flashlight",
            "Value": true
          }
        ],
        "Include": [
          {
            "FileName": "some_other_path_under_cfg.json"
          }
        ]
      }
    }
  ]
}
Sections can be used to conditionally include configurations based on game state, so the same config can be used for singleplayer and multiplayer, or deathmatch and teamplay. The only problem with this is that config files can change the game mode, so this will need to be well defined somehow.

InitializationOrder controls when each section is applied. Server config sections are always applied before map config sections that have the same InitializationOrder. You can have a server config applying something as a default, then a map config overriding things, then a server config forcing a setting back (e.g. time limit). Servers get a special order value that lets them set things after map configs to force things.

As much as possible config data should be unloaded after map start to free up memory.
Posted 7 months ago2021-06-12 09:37:37 UTC
in Yep, another coding issue: UTIL_ScreenFade Post #345694
You can modify the UTIL_ScreenFadeBuild function to make this work:
void UTIL_ScreenFadeBuild( ScreenFade &fade, const Vector &color, float fadeTime, float fadeHold, int alpha, int flags )
{
    fade.duration = FixedUnsigned16( fadeTime, 1<<8 );        // 8.8 fixed
    fade.holdTime = FixedUnsigned16( fadeHold, 1<<8 );        // 8.8 fixed
    fade.r = (int)color.x;
    fade.g = (int)color.y;
    fade.b = (int)color.z;
    fade.a = alpha;
    fade.fadeFlags = flags | FFADE_LONGFADE;
}
Located here: https://github.com/ValveSoftware/halflife/blob/c7240b965743a53a29491dd49320c88eecf6257b/dlls/util.cpp#L726-L735

The FFADE_LONGFADE flag indicates that a longer fade time can be used. The parameter to FixUnsigned16 has to be modified for both calls to use 1 << 8.
Posted 7 months ago2021-06-11 08:46:39 UTC
in Enhanced Half-Life (custom SDK/mod) Post #345690

Progress update:

Custom entity data parsing and entity instantiation

I've figured out a way to take control of entity data parsing as well as entity instantiation. These are two things that will go a long way to making mods more secure and allows for new features to be added.

Entity data parsing is the process by which the entity data in a BSP file is converted into actual entities. This code is now in the server dll which means you can have more control over it.

Entity instantiation is the process of creating the entity that the classname refers to. Having this in the server dll allows for more control and improves security, because it doesn't involve calling arbitrary functions based on untrusted input.

Potential uses of custom entity data parsing include implementing point_template, loading default keyvalues from a file, changing the entity data string to another format like JSON (albeit with some restrictions, see below) and adding input/output support.

Changing the data format requires the map compiler to be changed as well. Features like I/O support require map editor support as well and requires modifications to be made to the .map format since it doesn't have the flexibility needed to specify that kind of data (if you need to change it, you may as well switch to a format like JSON).

Potential uses of custom entity instantiation include marking entities as internal so they can't be spawned by mappers (for safety purposes), "synthetic" entities defined by config files instead of in code and custom entities defined in scripts (which you wouldn't be able to restore otherwise).

Here's an example of a synthetic entity config file:
{
  "BaseEntityName": "ammo_generic",
  "EntityName": "ammo_9mmclip",
  "EntityNameAliases": [
    "ammo_glockclip"
  ],
  "KeyValues": [
    {
      "Key": "model",
      "Value": "models/w_9mmclip.mdl"
    },
    {
      "Key": "ammo_amount",
      "Value": 17
    },
    {
      "Key": "ammo_name",
      "Value": "9mm"
    }
  ]
}
This is part of the proposal i wrote, it hasn't been implemented yet. Ammo entities can be described in terms of ammo_generic entities, so this moves a bunch of code into user-editable config files.

Combined with per-map config files that can override default files you can control what each entity turns into.

The next step after this is implementing reflection and replacing the old save data with that.

Technical information

The entity data string typically looks like this:
{
"wad" "\quiver\valve\halflife.wad;\quiver\valve\decals.wad;\quiver\valve\xeno.wad;\quiver\valve\sample.wad"
"chaptertitle" "C0A1TITLE"
"message" "Anomalous Materials"
"classname" "worldspawn"
}
{
"origin" "-424 280 -160"
"message" "ambience/crtnoise.wav"
"health" "2"
"spawnflags" "2"
"classname" "ambient_generic"
}
Entity data parsing is normally done in the engine, but there is an edge case that allows you to fool the engine into thinking it's already done parsing.

The first call into the server dll done by the engine during map loading is a call to DispatchKeyValue.

This keyvalue is always the classname key for worldspawn, the first entity in any map. Though it is possible for the classname to differ, this is forced back to worldspawn for security purposes.

At this point we can assert that the engine's parser is currently positioned right after the first { in the entity data string.

We can obtain a pointer to this string by first acquiring the server_t instance. This is possible by taking the string_t mapname member in globalvars_t and getting the pointer to the name using STRING(). This is the address of the name member in server_t. Subtracting the offset of that member in server_t gets a pointer to server_t.

server_t's worldmodel member is the BSP model, which contains a member entities. This is the entity data string.

Modifying it at this point to become {} will cause the engine to stop parsing the string. It will still try to call the worldspawn function which is an empty function. If it doesn't exist the engine will remove the world entity, so it has to be there.

The server will parse the entity data string and handle creation of all entities by itself. This behavior is currently identical to the engine, except it handles errors more gracefully. It won't stop parsing when it encounters bad data, instead it will try to skip past it to continue. This will likely fail since corrupted entity data is probably missing too much information.

This covers everything that happens when loading a new map. However entities are also created when loading a save game, so this also had to be handled.

When a save game is being loaded the first call into the server dll is a call to SaveReadFields to read in the data contained in a save game.

It will load all of the entity data stored in the save game, create all entities and then initializes them. If the save game is being loaded because the player is going through a changelevel then entities from adjacent maps that were marked for transition are also created from separate save game files.

The engine creates entities by using the classname stored in the save game's entity table block.

It then restores the entity by calling DispatchRestore.

This behavior is overridden by changing the classname to custom in DispatchSave.

The classname is also forced to custom in SaveReadFields for every ETABLE read in.

The engine will call the function custom for every entity it wants to create. This function is empty just like worldspawn and does not actually create anything. The name custom is special because the entity data parsing code in the engine also uses it to spawn entities it can't find a function for. This serves as a fallback to make sure that all works properly, but it should never be needed for that.

When DispatchRestore is called the server checks if it has previously seen a particular SAVERESTOREDATA instance before (identified by the map it was made for, and the landmark name associated with it). If it hasn't, it creates all of the entities that would have been created by the engine for that save game data.

The actual classname is stored in each entity's save data so it can be recreated from that.

This is needed because when entities are restored they also have to set up connections to other entities. If the entities don't exist yet this will fail and break things.

The result is the server dll handles creation of all entities by itself. The engine function CREATE_NAMED_ENTITY is also handled by the server dll so the engine does not create entities anymore, it only thinks it does.

Changing the entity data string format

The entity data string format can be changed to something else since it's parsed by the server dll.
The only restriction is that the string must start with data the engine can understand since it still parses that.

For example here's a version that uses JSON:
{
"classname" "worldspawn"
}
{
    "Entities": [
        {
            "ClassName": "worldspawn",
            "KeyValues": [
                {
                    "Key": "wad",
                    "Value": "\quiver\valve\halflife.wad;\quiver\valve\decals.wad;\quiver\valve\xeno.wad;\quiver\valve\sample.wad"
                }
            ]
        }
    ]
}

Other stuff

I've found a program that can be used to edit JSON files: https://github.com/json-editor/json-editor

This'll make editing config files a lot easier.
Yeah the sprites have the color because autoaim has a red color, and sprite coloring done through code requires monochrome sprites that will be shades of the given color.
Posted 7 months ago2021-06-06 21:14:14 UTC
in Enhanced Half-Life (custom SDK/mod) Post #345685
I forgot to add this:

Entity batch tool

I made a tool to perform batch operations on .rmf, .map, .bsp and .ent (Ripent) files. It can be used to find things in a map like specific entities, but it can also be used to modify them.

It uses CSharpScript to let you write scripts to apply to maps.

This script collects information about all official maps, specifically the number of items, weapons and monsters:
#load "Bootstrapper.builtin"

public class Diagnostics : ScriptProcessor, IDisposable
{
    const string DiagnosticsFile = "Diagnostics.txt";

    private readonly EntityCounter _itemsCount = EntityCounter.StartsWith("item_");
    private readonly EntityCounter _weaponsCount = EntityCounter.StartsWith("weapon_");
    private readonly EntityCounter _monstersCount = EntityCounter.StartsWith("monster_");

    private readonly StreamWriter _writer;

    public Diagnostics()
    {
        //Overwrite the old file if it exists
        _writer = File.CreateText(DiagnosticsFile);
    }

    public void Dispose()
    {
        _writer.Dispose();
    }

    public override void OnProcessFile()
    {
        if (IsAnyOfficialGameCampaignMap(SourceFileName.Name))
        {
            _itemsCount.AddFrom(Entities, out var itemsCount);
            _weaponsCount.AddFrom(Entities, out var weaponsCount);
            _monstersCount.AddFrom(Entities, out var monstersCount);

            _writer.WriteLine($"File {SourceFileName.Name}");
            _writer.WriteLine($"\t{itemsCount} items");
            _writer.WriteLine($"\t{weaponsCount} weapons");
            _writer.WriteLine($"\t{monstersCount} monsters");
        }
        else
        {
            Logger.LogInformation("Ignoring map {Name}", SourceFileName.Name);
        }
    }

    public override void OnEndProcessing()
    {
        _writer.WriteLine($"Total: {_itemsCount.Count} items");
        _writer.WriteLine($"Total: {_weaponsCount.Count} weapons");
        _writer.WriteLine($"Total: {_monstersCount.Count} monsters");
    }
}
The line #load "Bootstrapper.builtin" is a bit of magic that makes this class stateful across invocations. IsAnyOfficialGameCampaignMap is a built-in function that matches map names up to official map names through regular expressions. There could be false positives if somebody named their map in a specific way, but that almost never happens.

This script updates vanilla Half-Life maps to still work with some of the breaking changes made so far:
void ReplaceWorldItems(MapEntity entity)
{
    //Convert world_items entities to their respective entities
    if (entity.ClassName == "world_items")
    {
        switch (entity.GetInt("type"))
        {
        case 42:
            entity.ClassName = "item_antidote";
            entity.Remove("type");
            break;

        case 43:
            //Remove security items (no purpose, and has been removed from the codebase)
            Entities.Remove(entity);
            break;

        case 44:
            entity.ClassName = "item_battery";
            entity.Remove("type");
            break;

        case 45:
            entity.ClassName = "item_suit";
            entity.Remove("type");
            break;
        }
    }
}

void UpdateSuits(MapEntity entity)
{
    //Set the logon type to the original default
    if (entity.ClassName == "item_suit" && !entity.ContainsKey("logon_type"))
    {
        entity.SetString("logon_type", "LongLogon");
    }
}

foreach (var entity in Entities.ToList())
{
    ReplaceWorldItems(entity);
    UpdateSuits(entity);
}
The tool is still a work in progress so no release yet.

It can process a single file, a directory or a set of directories. I use it to process Half-Life, Opposing Force and Blue Shift maps (processed by the BS Updated conversion tool) to quickly check for uses of entities and to update them to make them work in EHL.

It can technically also just copy maps from one directory to another, but that would be overkill.
Posted 7 months ago2021-06-06 21:06:34 UTC
in Enhanced Half-Life (custom SDK/mod) Post #345684

Code generation

I've improved the code generator's performance and speed. Code generation is now done on a per-file basis, meaning the generator assumes each file contains at most one class and will generate code for that class if required. This is done because there is no way to know what kind of changes have been made in a file unless the file is parsed, which is the slowest part of the code generation process by far. Instead the generator checks for the last modification time on the file to determine if it needs to reparse the file.

As such all entity classes have been moved to their own header and source file pair. This in turn slows down compilation but due to the increase in efficiency the code generator is much faster when doing partial rebuilds. Typically you'll be modifying only a few files at a time, so compilation takes only a few seconds. A full rebuild on my system (SSD with quad core) takes a few minutes but after that it's fast enough, much faster than the previous approach of using precompiled headers in the code generator (which still had to process a lot of code every time, and always regenerated all files forcing a full rebuild).

The LINK_ENTITY_TO_CLASS macro is no longer used, the code generator takes care of that part now as well.

Additionally i've changed the format used to specify attributes to use JSON. This is because the use cases for the code generator have changed to the point that i was implementing a worse version of JSON, so i switched to it to take advantage of a widely used format with many existing parsers.

It now looks like this:
#pragma once

#include "CBaseEntity.hpp"
#include "CEnvSpark.generated.hpp"

constexpr int SF_SPARK_TOGGLE = 1 << 5;
constexpr int SF_SPARK_START_ON = 1 << 6;

class EHL_CLASS("EntityName": "env_spark", "EntityNameAliases": ["env_debris"]) CEnvSpark : public CBaseEntity
{
    EHL_GENERATED_BODY()

public:
    void    Spawn() override;
    void    Precache() override;
    void    EXPORT SparkThink();
    void    EXPORT SparkStart(const UseInfo& info);
    void    EXPORT SparkStop(const UseInfo& info);
    void    KeyValue(KeyValueData* pkvd) override;

    EHL_FIELD("Persisted": true)
    float m_flMaxDelay = 0;
};
The code generator will now also raise an error if you use unknown attributes or incorrect attribute values (e.g. a string value for Persisted, which is a boolean).

Error handling is designed to tie into Visual Studio's error handling system: the format matches that used by MSBuild, so the errors are listed in the Error List panel and will link to the right file, line and column number when double clicked in either the Error List panel or the Output panel. This makes debugging codegen errors much easier.

The code generator is fairly robust when it comes to handling compilation errors. If you compile your projects and there's an error the files generated that time will be regenerated the next time you compile to ensure any invalid codegen (e.g. missing/invalid attributes) is corrected. There are still a few edge cases where it could fail to do this correctly but i'll try to account for those.

In the event that bad codegen isn't detected, you can wipe all generated code by building a special project. Each project that has codegen enabled gets a CLEAN_CODEGEN_<project name> project that does this. They're also organized under a solution folder in Visual Studio that lets you build all of them at once to wipe all codegen in one go.

Additionally, for Visual Studio i've added a cpp.hint file to tell Intellisense how to deal with the codegen macros. Without this file it can't properly parse class declarations and lists functions as having no definition, which is pretty annoying.

Other stuff

For Visual Studio i've added a .natvis file to tell the debugger how to display entity classes in the debugger. This lets you easily see the classname, targetname and target of any entity you have a pointer of:
natvisnatvis
You'll have to click the refresh icon since these are functions. This makes debugging a lot easier, especially when an entity has an unknown class (e.g. AI code where you want to know the target entity's class).

The weapon selection client command has been changed to use an actual command name. Previously this worked by sending the weapon name and then checking for a "weapon_" prefix. If you were to name a weapon with a prefix other than that you'd never be able to select it through the weapon HUD. Now it works like all other client commands.

CGameRules has been given a virtual destructor to ensure that they can clean up properly on deletion. If a gamerules object destructor has to do any cleanup like freeing memory then this would not work properly in vanilla.

I've fixed a bunch more compiler warnings as well.

All headers now use the .hpp extension for consistency. This also means that all code is now expected to be compiled as C++ code only. All headers now also include their dependencies so each individual header should compile when included by itself. This also means that the include order is not as important as it was before (you had to include extdll.h, util.h and cbase.h in that order).

Including cbase.h will include a bunch of common headers now. Since precompiled headers are in use many source files don't include anything anymore but i may change this to allow the projects to be compiled without precompiled headers if needed for some reason.

Lastly, here's a look at the current project structure in Visual Studio:
project structureproject structure
You can see both CLEAN_CODEGEN projects, the projects that CMake always includes (building INSTALL deploys dlls to the mod directory) and the client and server dlls.

The directory structure makes finding entities pretty easy, though there are some cases where entities had to be put somewhere else to organize things properly.

The warnings indicated by the green squiggles involve the Activity enum, which is an unscoped enum. That hasn't been changed since the name based lookup still relies on the old names (ACT_ names).

That about covers it for work done. I have a bunch of stuff planned for the future but i'll discuss that when i've got some more work done:
todotodo
Posted 7 months ago2021-06-06 21:06:20 UTC
in Enhanced Half-Life (custom SDK/mod) Post #345683

Class hierarchy updates

Part of the item updates also involved refactoring the class hierarchies. All items now derive from a new CBaseItem class that controls shared behavior such as pickup and respawn logic. The CItem class is almost empty, the CBasePlayerAmmo class has been stripped of most of its code and the CBasePlayerItem class's code has also been stripped down since all 3 had very similar code.

Further entity class refactoring summarized as follows:
  • CBaseDelay delayed triggering has been merged into CBaseEntity, giving all entities the ability to delay triggering of the "target" keyvalue, but only if the entity uses SUB_UseTargets for this. This eliminates the use of a non-virtual override which could cause inconsistent behavior.
    • What remains of CBaseDelay has been reworked into CDelayedUse, which handles the delay triggering logic as before. To be removed when delay triggering is moved to a dedicated list of queued events.
    • Master entity string management has been moved from CBaseToggle to CBaseEntity. Duplicate master entity strings have been removed from other classes. This eliminates the use of a non-virtual override which could cause inconsistent behavior.
  • Door-specific toggle state functionality has been cleaned up to eliminate the presence of a useless virtual function. SetToggleState was never used and has been removed.
  • Entity-specific members originally stored in CBaseToggle have been moved to their respective classes, such as the counter variable for trigger_counter. CBaseToggle now only contains members for linear and angular movement, which is its intended purpose.
  • CFuncMortarField, CFuncIllusionary, CBaseCharger now inherit from CBaseEntity instead of CBaseToggle
  • CScriptedSentence now inherits from CPointEntity instead of CBaseToggle
  • CSqueakGrenade (snark) now inherits from CBaseMonster instead of CGrenade
  • CGrenade now inherits from CBaseAnimating instead of CBaseToggle
  • CBaseTrigger now inherits from CBaseEntity instead of CBaseToggle
  • CMultiManager now inherits from CPointEntity instead of CBaseToggle
  • CGenericCycler has been merged into CCycler (CCyler used to be a base class for obsolete HL alpha cine_ entities which used non-existent models)
  • CBaseTrigger members have been moved to the classes to which they belong
  • CBasePlayerItem has been merged into CBasePlayerWeapon
  • CBasePlayerWeapon has been renamed to CBaseWeapon
  • CBasePlayerAmmo has been renamed to CBaseAmmo
  • trigger_counter has been removed since it's an inferior, buggier version of game_counter. (it could break entirely if its master entity were locked since it still counts triggers regardless, and only triggers when it hits exactly 0)
  • The debug-only entity trip_beam has been removed. This entity was never used anywhere.
CBaseMonster still inherits from CBaseToggle for now, and CBaseToggle still inherits from CBaseAnimating. Neither should be the case (CBaseToggle is for brush entities, CBaseAnimating is for studio model entities) but this is needed because a single entity func_guntarget is a monster to make itself target-able by monstrs (inherits from CBaseMonster) but also uses CBaseToggle's linear movement code (it's basically a door that moves between two points).

It's used for the Hazard Course target range and can't be changed right now. Hopefully if i can implement parenting support this can be changed (e.g. like npc_bullseye).

I've also removed all uses of pev->noise, pev->noise1, pev->noise2 and pev->noise3. These are used internally to store off the sounds made by certain entities. The change is part of the "CBaseEntity everywhere" goal and involves the removal of all uses of edict_t and entvars_t.
These variables were being used in confusing ways (multiple #define aliases that made it difficult to find where the values were coming from) so this improves readability as well, and eliminates some of the last remaining #defines.

New and updated entities

Some entities have been updated:
  • game_player_equip now saved and restores its members, allowing it to be used in singleplayer.
  • player_weaponstrip has new keyvalues:
    • Strip Weapons Yes/No (Default Yes): Whether to strip all of the player's weapons
    • Strip Suit Yes/No (Default No): Whether to strip the player's HEV suit. If the flashlight is on it will be turned off.
    • Strip Long Jump Module Yes/No (Default No): Whether to strip the long jump module.
  • New entity: player_sethealth. Sets the player's health and/or armor. Can apply to the activating player or all players. Can set health to any value from 1 to 100, can set armor to any value from 0 to 100. Does not deal damage, shows no HUD icons or damage indicators, cannot kill the player. Useful for setting an initial health value and/or giving armor without playing sounds. Shown in the video when the button is used to set the player's health to 1.

Bugs fixed

  • CWreckage (cycler_wreckage) saved a time value that was actually an int, which would result in corrupted values on restore if the timebase differs. Now saved as a float.
  • Weapons would try to drop the weapon that was picked up instead of the newly created weapon when the weapon gets picked up. Now the weapon being respawned will be dropped, as it should be.
  • When the server is near the edict limit (< 100 free edicts) weapons would be respawned with an incorrect delay. It should be current time + delay, but was current time + current time + delay.

Entity list improvements

I've added a new class that provides an API for creating and destroying entities, as well as iterating over them. It's still a work in progress, but it solves a few problems. For one the classname string is now managed by it so there's no need to worry about strings not outliving the entity, and it sets the classname automatically so there's no need to set it manually when creating entities through code.

To make this work LINK_ENTITY_TO_CLASS now also registers entities in a global dictionary to allow name based lookup. I've also added support for "alias" names that ensure aliased entity names such as weapon_glock not only map to weapon_9mmhandgun but also automatically change the classname to the intended name.

The GetClassPtr function has been removed since it is badly designed and doesn't handle creation properly (classname is never set). The CREATE_NAMED_ENTITY engine function is now obsolete and has also been replaced by the new entity list API.
Posted 7 months ago2021-06-06 21:05:43 UTC
in Enhanced Half-Life (custom SDK/mod) Post #345682

Progress update:

Item updates

item updates
Item entities have been updated with new features. When i refer to items i mean entities classified as one of these types:
  • Pickup items (health kit, battery, suit, long jump, antidote)
  • Ammo items
  • Weapons
For all features they default to the game mode's defaults if not specified.

New features:
  • Item respawn behavior can be overridden. It can be set to always respawn (like in multiplayer) or never respawn (like in singleplayer).
  • Respawn delay can be overridden. Anywhere from instant (delay 0) to some time in the future that could be seconds, minutes, hours, etc.
  • Respawn position can be overridden. By default it respawns where it was when picked up, but using the "Original" respawn position it will respawn where it was placed. This matters when the item is placed above or on top of another entity that may not always be there, like a func_wall_toggle. When using "Current" position (the default) it will respawn below the other entity, when using "Original" it will respawn on top of the entity. Very useful for hidden items like a weapon hidden in a toggle-able ceiling.
  • The method used to make the item fall to the ground can be changed:
    • PlaceOnGround: The item is placed on the ground by making the engine drop it to the floor. If the item falls through the world (e.g. clipping into a brush) it will be removed.
    • Fall: The item falls to the ground by applying gravity.
    • Float: The item floats in the air and does not drop. Unlike the other two modes the item's pitch and roll are not zeroed, which allows the item to be posed as desired.
    • Pickup items use PlaceOnGround, ammo and weapons use Fall (carried over from vanilla).
  • The ability to pick up items that are falling can be controlled. By default "Fall" mode items cannot be picked up until they have fallen on the ground. If the item is also respawning in the air using "Original" position mode this can make a difference.
  • The item "clatter" mode can be overridden. This is the sound played when an item bounces on the ground. Normally it only plays when dropped by a player, this setting allows it to always or never play this sound.
    • The clatter sound can also be changed.
  • The item can be set to stay visible during the respawn delay. Normally it is made invisible until it respawns, this allows it to remain visible, useful for e.g. armories where players can see the items while they're respawning.
  • The item can be set to flash on respawn. This is enabled by default and causes a muzzleflash effect to be applied to any nearby studio model entities. It can be disabled to make a respawning item less conspicuous.
  • The respawn sound can be changed. Setting it to a sound like common/null.wav effectively disables it.
  • Two new trigger targets have been added to trigger something when an entity respawns (aka materializes) and when it has been picked up and becomes invisible (aka dematerializes). Seen in the video when the isotope ammo box toggles the green sprite on and off.
  • All items can have their world model changed to a custom one.
Now the features specific to each type of item.

Pickup items:
  • Health kits:
    • Health kits have a custom capacity option now. Any positive value including 0 (e.g. fake healthkit) can be used.
  • Batteries:
    • Batteries have a custom capacity option now. Any positive value including 0 (e.g. fake battery) can be used.
  • HEV Suit:
    • The "Short Logon" spawnflag has been changed to a keyvalue to control the type of logon. Available options are:
      • No Logon: No message is played, this is now the default.
      • Long logon. The entire logon message is played, this was the previous default.
      • Short logon. The first part of the logon message is played.
  • Long jump:
    • The pickup sentence can be disabled.
Ammo items:
  • The amount of ammo given can be changed. One "unit" of ammo is one of whatever the ammo type is. One unit of 9mm ammo is one 9mm bullet, one unit of RPG ammo is one rocket, etc. The amount can be 0 (e.g. fake ammo).
  • The ammo pickup sound can be changed.
  • New ammo entity: ammo_generic. This ammo entity lets you specify the name of the ammo to give, and does not set a model by default. Useful for invisible ammo items. The ammo names used are internal names, which is something that will be changed later on.
  • New ammo entity: ammo_all. This ammo entity gives the player all of the ammo types known to the game. The amount of units of ammo to give can be set, including a special value of -1 which will give the maximum amount. Useful for quickly topping off a player's ammo.
Weapon items:
  • The default primary ammo amount can be changed. Can be 0 to give the player an empty weapon. If the hornet gun is given with no ammo it will not regenerate ammo since it has to be switched to first to do so. Useful for giving a fully loaded MP5. Does not apply to MP5 grenades.
  • The weapon pickup rule can be changed:
    • Default: you can pick up the weapon if you don't have the maximum amount of ammo for this weapon, or if you don't have the weapon.
    • Always: you can always pick up the weapon, even if you wouldn't get anything out of it. Useful for making sure a player has a weapon without leaving them extra ammo.
    • Never: you can never pick up the weapon. Basically turns the weapon into a prop, there are probably better and cheaper ways to do that though.
    • NoDuplicates: you can pick up the weapon if you don't have it, but you can't pick it up otherwise. Useful for weapons that should only be picked up if the player doesn't have it, without giving them any ammo, while leaving the weapon lying around. Potentially very useful for making maps where players can lose their weapons and can backtrack to restock on missed weapons, as well as multiplayer maps where you don't want players hoarding weapons.
  • Weapons will now also retain their sequence value on respawn. The Crossbow and Gauss gun models in particular have a second "on side" animation that avoids clipping through the floor, this lets you set it and keep it after it's been picked up once.
The video shows some of these new features in action.
The bug is in the engine so if you want this to work you'll need to implement music playback in the client dll. You could adapt this tutorial to use FMOD, but you'll need to change a bit since Source and GoldSource have differences in many areas.
Posted 7 months ago2021-06-05 15:00:12 UTC
in Coding issue: the monstermaker entity Post #345678
Take a look at the code used for the Alien Slave's attack: https://github.com/ValveSoftware/halflife/blob/c7240b965743a53a29491dd49320c88eecf6257b/dlls/islave.cpp#L719-L763

You could also just use Blue Shift's env_warpball entity as a base: https://github.com/Solokiller/halflife-bs-updated/blob/17f13bc65ade2dd364b10dd69e64c7bcd798d359/dlls/effects.cpp#L2282-L2540

It does pretty much what you want to accomplish.
Opposing Force handles HUD colors a bit differently since the CTF gamemode requires changing colors.

To change the default color you need to change this code instead:
https://github.com/Solokiller/halflife-op4-updated/blob/bfafe3f22ed49a447d6650a5a499723a71b247f7/dlls/cdll_dll.h#L171-L175

Change RGB_HUD_COLOR to the color you want to use.

If you want to change it dynamically (e.g. with cvars) then you'll need to move this code:
https://github.com/Solokiller/halflife-op4-updated/blob/f4e0ed692fe47714e2bfc8097fd10c8ff5b7bbd7/cl_dll/cdll_int.cpp#L170-L171

To here:
https://github.com/Solokiller/halflife-op4-updated/blob/f4e0ed692fe47714e2bfc8097fd10c8ff5b7bbd7/cl_dll/cdll_int.cpp#L264-L269

Put the code before the voice manager code like this:
void DLLEXPORT HUD_Frame( double time )
{
//    RecClHudFrame(time);

    UnpackRGB(giR, giG, giB, RGB_HUD_COLOR);

    GetClientVoiceMgr()->Frame(time);
}
And change it so the RGB value is set to whatever you want it to be. If you're using separate cvars for the color then it should be like this:
giR = CVAR_GET_FLOAT( "hud_red" );
giG = CVAR_GET_FLOAT( "hud_green" );
giB = CVAR_GET_FLOAT( "hud_blue" );
Note that if you do this, CTF's HUD colors will no longer work since you're overriding the color every frame.

You may also want to cache the pointers to the cvars so avoid the costly lookup every frame.