HentHighSchool Development Forum

Please login or register.

Login with username, password and session length
Advanced search  

News:

collapse

Pages: [1]   Go Down

Author Topic: Dev Blog  (Read 15387 times)

Shilo

  • Moderator
  • Hero Member
  • *****
  • Offline Offline
  • Posts: 2232
    • View Profile
Dev Blog
« on: April 05, 2020, 05:50:39 pm »

Hi all!

Some of you have voiced their concern about the lack of progress updates. After all, the last version 1.9.5 was released more than 1.5 years ago. And while the next release is still some time off, I want to use this thread to provide you with some insight into the changes we’ve been making in the internal development build.

I’ll keep the thread locked to prevent cluttering with other comments, so future updates can be found more easily. And I’ll also not write up everything at once. Mostly because it takes me forever to write stuff. But also for teasing. ;)

But without further ado, let’s start this blog with the first new thing:

UI Notifications

Probably the new engine feature that is most noticeable for players in the next update. Up until now, the game would only inform you via colored floating numbers about changes to the global average stats of your students. However, this system has several limitations:
  • Since it only shows changes to the global average, it fails to properly communicate the effects of the event that is currently playing out on the affected NPCs. The more students you have in your school, the less impact the individual changes of an event will have on the average value.
  • The average value may also misrepresent the effects an event may have on an individual if there is another group that is affected in the opposite direction. Example: You could have an event where you are making fun of a single student in class. While the other students may laugh about that and raise the overall happiness, the one student you are making fun of may actually have his happiness lowered significantly. But that effect would not be visible if you just looked at the resulting average.
  • Because the changes were only shown when time passed, you may not even see the results of events that take place without time progression until you encounter a different, unrelated event. This also causes the results to be mixed up with stat changes that occur naturally, like school subject influence and the population’s mind adjustment.

To solve this problem, we added support for several event operations to report changes right when they occur.
However, displaying each change to each stat for every NPC and every operation individually would lead to a copious amount of notifications (which would keep going as floating numbers for several minutes even after the event ended). So the system also includes several mechanics to reduce the noise:
  • Instead of immediately showing the notifications when an operation is performed, the change is first recorded into an internal list. It is then only shown if either the event finishes or by triggering a new operation inside the event that explicitly starts displaying the gathered notifications. This makes it possible to accumulate changes to the same stat of the same NPC throughout the event, even if it happens via multiple operations. But if the event author wants to display them in a timely manner, they are still free to do so.
  • There is also a new operation to assign NPCs to a named “Notification Group”. When displaying the gathered notifications, all individual stat changes for all NPCs in a group are averaged and only the average is shown as notification, with the name of the Group being used as label. So in the example from before, you could have individual notifications for the student you made fun of (which show up with his name) and then put the entire rest of the class into a Notification Group named “Laughing Students”, which would then show the average change for all of them along with the number of NPCs currently in that group. The Notification Groups can also be useful if you want to hide an NPC’s true name for story reasons and avoid giving the name away via notification label. Just put that NPC into a group with the fake name you want him to have. The group assignment only persist for the duration of the event's execution, but are passed down to Remote Event executions.
    For convenience and as safeguard, NPCs who have their stats changed via the "Person Stats by List" operation are automatically considered part of a group (which will be displayed with a name like "Persons"), unless they are already part of an existing group. It is generally preferable to name your groups explicitly at the start of an event execution.
  • It is also possible to define which stats are recorded for notifications under which circumstances. We don’t need to keep track of Energy notifications because the player already has a big UI element that shows that value at all times, and the stat is not relevant for NPCs. And we don’t need to keep track of Loyalty and Lust for the player character because these stats have no use for him. Likewise the Grunge stat is only used by the player, so we don’t need to track it for NPCs.

This new feature has only just recently been added to the engine and we are still in the process of updating events to make proper use of it, since adding the Notification Groups to avoid flooding with messages is a manual task. Which makes this one of the reasons why the game is currently not in a releasable state.
The global stat notifications still exist, of course. This new system is just a more fine-grained variant.

Notifications are currently supported for stats, skills, and body sizes. I am also considering to track changes to the Relationship value in the database, if it does not affect performance too much. Displaying entirely custom notifications via VEE operation may be planned in the future but is currently out of scope. Spinner has also requested some more operations and adjustments, which I'll provide in due time.

While it may not seem like a spectacular feature at first, we think it really adds a feeling of agency and meaning to events and your decisions: Whether you praised a student, scolded them or sent them to detention barely seemed to make any difference. But now the consequences of your choice on that student are immediately made known by showing you the changes in their loyalty, happiness and corruption.
« Last Edit: April 05, 2020, 06:00:08 pm by Shilo »
Logged

Shilo

  • Moderator
  • Hero Member
  • *****
  • Offline Offline
  • Posts: 2232
    • View Profile
Re: Dev Blog
« Reply #1 on: April 07, 2020, 08:04:07 pm »

Global Variables

Global Variables are a new type of variable in the VEE and are a step towards readying the game for modding support. They are available for all primitive variable types: Integer, Double, Boolean, String and Date and can be quickly created by converting their non-global counterparts.

In order to explain why I consider them necessary for proper modding support, I need go a bit into how I plan the modding system to work:

In the game’s current state, mods only work by adding their files directly in the game’s directory, potentially replacing files from the official release version. With the modding framework, each mod should reside in its own directory next to the official release files. Via a mod configuration interface within the game’s main menu can you then choose which of these individual directories (in other words: mods) should be included in the game you are about to start, as well as the order in which they are included.
Whenever the game engine then needs to lookup something in the file system, it will also go through the list of included directories and check if any of them have resources with the same relative path (from its respective directory root) as the resource that was requested. If the path matches one of a resource further up in the ordered directory list (including the base game), it will be used instead of the original one.
In cases where the game engine wants to access everything in a specific subdirectory (for example to show a random image from a folder), it will simply add the resources from the mod to the existing one if they are in the same relative subdirectory.

However, simply replacing existing events in their entirety with custom ones could lead to problems because of the concept of Variable References that we have been using until now. Variable References allow us to use variables defined in other events by referencing them via the event’s relative file path and the ID of the variable inside the event.
Most of the quests in the game have a variable in the first event of the quest line that keeps track of the current progress in that quest. All subsequent events of the quest line then reference that single statekeeping variable. But if a mod decided to replace that original starting event with a completely different one, where the statekeeping variable did not happen to have the same ID as the original one, then all other events of the quest line would no longer be able to reference that variable and would break.

This is where Global Variables come into play. Unlike regular variables, the values of Global Variables are not stored in the VEE variable itself. Instead, the data containers for Global Variables are defined by individual XML files where each container is given a unique name, data type, optional description and default value. These containers are then stored in a separate list by the game engine, where the VEE proxy variables can simply reference them by their unique name. So instead of having Variable References that point to a single statekeeping variable in an event, you would use Global Variable proxies instead to point to a named shared container that is stored outside of any events.

And while the initial definition of each Global Variable in a separate XML file is a bit cumbersome, they add additional clarity and intent to event authoring by making you explicitly document which variables are intended to be used across multiple events.

The corresponding VEE menu will show you a list of all defined Global Variables containers to which you can bind the proxy variable. A full list of all Global Variables is also available in a new tab in the debug menu, where you can also modify their current value. This makes it easier to debug quest progression (and to cheat, but probably also to screw things up – use at your own risk).

Variable References will of course continue to work and still have their place to link to variables within the same event for the sake of avoiding VEE clutter. It just means that events that reference variables from other events are not guarded against breaking from mods. We won’t rework the existing events right away, but perhaps as the need arises.
Logged

Shilo

  • Moderator
  • Hero Member
  • *****
  • Offline Offline
  • Posts: 2232
    • View Profile
Re: Dev Blog
« Reply #2 on: July 12, 2020, 02:06:37 am »

Error Checking Revamp

This feature is just a minor one and is primarily of consequence to developers, though players may benefit from less bugs as a result.

When the editor was checking events for structural errors, the old version was simply reporting any findings as individual lines of text in a console window.

A major drawback of that system was that it required to provide all necessary information in the error message, for example the ID and name of the operation that caused the issue. That error message is custom-made for each of the countless operations we have in the engine, though, and not all of them were always providing that information. It also made the process of adding just one more piece of information (the name of the containing event) a whole lot of work.

But it had to be done at some point, so I went in and reworked the entire system with all the error messages and changed it to produce a list of structured data, rather than just a single block of text. The structured data now includes stuff like the name of the operation, its ID, the containing event file and a severity level. Some of that information was previously contained in the error message itself, which has been shortened now as a result.

Why do all that in the first place?
Aside from being able to display errors in a more unified and structured manner, having the name of the containing event is also important: we now also have a new option in the Dev Tools menu that lets us check all events for errors at once, and all results are collected in a single table. This makes it much easier to fix any issues that would otherwise pop up during gameplay. Previously we would have needed to open and check each event individually, which is not really feasible with the more than 1400 event files that we currently have in the game. As you can see from the screenshot, we still have some cleaning up to do before the release.

Another benefit: while the old system would only report actual errors, the new system also has a severity associated with the message and can be used to report informative stuff or warnings that are not necessarily errors. There is also the severity level “autofixed”, which is used when the error checking process caused the operation to automatically repair itself.
And in case anyone wants to copy-paste the errors like they were able to do with the console version: the table output can also be exported as CSV file.
« Last Edit: July 13, 2020, 01:04:08 am by Shilo »
Logged

Shilo

  • Moderator
  • Hero Member
  • *****
  • Offline Offline
  • Posts: 2232
    • View Profile
Re: Dev Blog
« Reply #3 on: July 13, 2020, 01:03:35 am »

The little things

The previous blog entries went into the details of some new systems because they are elaborate enough to warrant individual posts. But we should not forget about the small changes that may not seem like much on their own but hopefully help to improve the overall experience both for developers and players.

This post will only cover things that changed in the engine itself, and not the numerous improvements on the content side. It's also just a simple rundown of the commits that have taken place, so don't expect too much fleshed out details.

Let’s start with a slightly more noticeable change:
Showing decision options to the player now supports Font Awesome at the beginning of the text. To do this, simply have the decision start with the name of the icon, for example “fa-book”. It will then be replaced by the actual icon when displaying it. An example where we use this is the revamped Smartphone (see the attached screenshot). Previously the use of the icons was limited to Button Events and UI buttons.


There is an ongoing effort to decrease the number of hardcoded “magic numbers” in the engine and make more stuff configurable, to allow for easier modding and use in other scenarios in the future. The following changes play into that:

- DetentionLocationProvider will now use the first rule with "detention" (case-insensitive) in its name instead of looking hard-coded for "Detention rules".
- More population-related properties can now be configured in the Scenario Config.
- The maximum number of students per class can now be configured via the Scenario Config. A new VEE constant is available that returns the current value of the config.
- ScenarioConfig is now visible in the Game Objects debug tab, so properties can be easily checked and changed during ongoing play.


Some new VEE operations or new variants of existing ones have been added as well.

- "Item by Name" operations now use the regular "Name" property of an item by default and have a link variation for the "Display Name".
- "Set Rule Active" is now named "Set Rule Available" in code and XML.
- "Set Rule Choice Active" is now named "Set Rule Choice Available" in code and XML.
- Added a new operation "Set Rule Choice Active" (i.e. same name as the old operation) that can be used to set the currently active Rule Choice from VEE.
- Added "Get Rule" operation to acquire a Rule object for use with reflective property modification.
- Removed "Check Favor Indicator" condition. Favor indicators are handled entirely with Status Flags from Status Effects now, so there is no need to have a dedicated operation for the old stuff.
- Removed "Person Has Birthday" condition. The same can be achieved by getting the actual birthday date and some simple comparison operations. There is also a Function Library event that handles this.


And then there are the things we changed because it just seemed better that way. Some of these may require modders to make small adjustments to their mods when we release the new version, though.

- Rules now apply the actual value for a Reputation change on each day. Previously, it would only apply 1/5th of the value to avoid too rapid growth. This behavior was confusing and entirely opaque to modders.
- CurrentOutfit is now always calculated whenever its checked.
- While showing a teacher in the management panel, their OutfitName will be set to "Work" while updating their paperdoll and back to the previous value afterwards.
- Adding/Setting the relationship value in the database now clamps it to the [-100;100] range. Previously it was only clamped when reading the value back to code, which could give you values outside that range when querying the database directly.
- Clubs will now validate if their current members have the correct gender for the club on a daily basis and kick out anyone who no longer fits. So if you give someone a gender transformation drug, they will no longer be able in a club that is not meant for that gender.
- The calendar note tooltip at the bottom now only shows unfinished entries.
- Adding or creating calendar notes with a blank name now cause an exception.
- Deleting calendar notes now only considers the name and not the other properties (the previous behavior was a bug).
- Database Query operation now has an additional input to end the iteration prematurely and also frees up resources when activating the Finished output. The query operations are actually reading the entire list of results when you execute the query and then store it in memory (which can be quite a lot, depending on the query) for when you iterate through it in subsequent uses of the operation. Using the new input when you don’t iterate until the end helps to keep that memory footprint low.
- VEE operations that show an image on top of them in the editor now preserve the original aspect ratio of the image instead of stretching it to the full size of the operation.
- Removed all remaining uses of "AsParallel()" in List Filter Club, Job and Stat Range operations. This could actually improve performance in cases where these operations were still used.
- Removed hardcoded randomization of arousal and energy in daily NPC stat update.

Last but not least, there are also bugfixes. Some of these may have actually had a negative effect on gameplay but were really subtle. They were only found due to the long and rigorous testing by the events team, who created dedicated test cases to reproduce these issues when they had a suspicion.

- Random Chance now works for values from 0 to 100, rather than 1 to 99. Due to the way the old code worked, even providing 100% as chance value could lead to the operation triggering the “Not Passed” output with a 1% chance.
- Fixed bug causing PersonStatsByList operation to incorrectly calculate the average value if it was used for multiple stats in the same operation.
- Fixed one constellation of PersonTraits operation removing the trait when it should actually add it.
- Duplicating SeqCond_CompareDate now properly copies link variations.
- Duplicating a ShowRandomImage operation now also duplicates the separate output links correctly, if that option is set on the source.
- Fixed some Item operations not taking over their link variations when cloning them.
- Fixed bug causing the CurrentOutfit to not properly resolve to the Club Outfit because it was comparing the name of the club location to the actual location.
- Fixed off-by-1 error potentially preventing the last item in a location from being picked up by NPCs.
- Made sure that String-to-Number conversions in VEE operations use the invariant culture, to avoid unexpected issues on specific locales.
- Fixed bug causing exception when attaching/detaching an event to a person in Try-phase while having multi-threading disabled.
- Database input field in debug menu now accepts return and tab keys.
- Database input field in VEE menu now accepts return and tab keys.
- SetPersonTextColor operation was reading variables at the wrong index.
- Fixed String Pad operation not having an output link.
- Check Rule condition now makes sure that rules have been loaded when pasting the operation.
- Fixed bug causing status effects that modify the maximum value to change the minimum value instead.
- Fixed bug causing the reloading of events in a location subfolder to also be added to the parent folder.
- Special characters now only get a random head assigned for the gender slot they are missing, rather than both.
- The Frontend now disappears and stops the task bar status after the Initialize event, rather than the StartEvent.
- Classes now only allow to add your own students to them, which fixes a bug that assigned expelled students to the "spare students" class.
- If a GameMind for the current scenario does not contain a stat adjustment for a specific stat, this will no longer throw an exception but just skip the stat.
- No longer throw an exception during daily population stat adjustments if the scenario defines no mind data.
- Fixed exception when creating second VEE directly from new process where it skips the Frontend.
- Description fields of objects in File Editor now support multi-line text.
- Fixed clubs not applying their stat changes at the end of their meeting.
- Clubs now only apply their stat changes if the person is in the location of the club meeting.
- Fixed adding/removing a person to/from a club potentially doing so one more time than intended.
- Adding a person to "no club" or no club will now remove them from their current club and no longer throw an exception.
- Pending autosaves are now also done after clicking on task buttons, interactions and using items, rather than just passing time.
- The current day is now marked as last autosave day before doing the save, so it is correctly reflected in the save file.
- Fixed typecast error in PersonStatsByList.
- Set Inventory Image operation no longer throws random exceptions during error checking.
- Bitwise Integer Math operation no longer requires a variable connected to B if ONLY the "NOT" input is used. It still does in all other cases.
- Corrected layout resizing of school subject description.
- Using up an item now clears the item details from the inventory screen.

And that's about it. I hope the current public release does not seem that much worse. After all, you probably don't even notice most of these issues unless you know what's actually supposed to happen in that very moment.
Logged

Shilo

  • Moderator
  • Hero Member
  • *****
  • Offline Offline
  • Posts: 2232
    • View Profile
Re: Dev Blog
« Reply #4 on: December 23, 2020, 01:21:19 am »

Modding Framework

The modding framework was already mentioned in previous blog posts, but let’s take another look at it.

My original plan was to not include the modding framework in the upcoming 1.10 release because we are already introducing so many other changes in that release. It seemed more appropriate to get a somewhat tested version out first and gather some feedback on technical issues there before opening yet another can of worms that could have negative performance impacts and concerns large parts of the engine.

However, there is also a flipside. The modding framework had been developed more or less steadily  in a separate code branch for a long time. That ultimately leads to more diverging code bases and regular maintenance effort when syncing them back up. It was effectively doubling the workload for certain parts because new code in the main release was written in an outdated way that needed to be changed again when merging it into the feature branch.
We are also toying around with the idea of migrating from VB.NET to C#, which would be least painful if we did not have to deal with multiple parallel development branches either.

So I decided to reintegrate that branch into the trunk and add the modding framework changes into the main codebase for the next release. To lessen the potential impact, there is also a legacy mode that ignores all the modding stuff and for the most part just delegates to the same underlying system calls that the engine has been using in the past (whether the legacy variant will be the default or an opt-in fallback in the next release remains to be seen).
I say “for the most part” because there are still countless places in the code that needed to be changed to point to an abstract framework, which in turn then does the actual legacy system calls or includes mods. Not all of them could be delegated exactly as they were, so it is possible that new bugs are introduced as a result of this, although we do our best to catch them in the early testing stage.

One major change that we had to make as part of the overhaul is to make sure that all scenario-specific resources use a file path that is relative to the root directory of that scenario.
Example:
  • In 1.9, the image paths that were referenced in events, items, etc. looked like this:
    Schools\NormalSchool\Images\EventPictures\Location\Park\ParkDate.jpg
  • In 1.10, they will look like this:
    Images\EventPictures\Location\Park\ParkDate.jpg

“Schools\NormalSchool” is the root directory of the scenario, so there is no need to explicitly declare it in events of the scenario. We are basically restricting the resources to be in a subfolder of the actual scenario that is using them. But I don’t think that using images from a different scenario in your own scenario was ever an actual use case. If anything, this was more than likely a hindrance and had mods like Lexville require you to copy images from the main game into a different “ModSchool” scenario.
While there is some fallback code that will attempt to also find resources if they still start with with the “Schools\NormalSchool” part of the path, it’s still recommended to update mods to the new format to be fully compatible with the new release.

Using the modding framework is pretty simple beyond that. There is now a new folder in the scenario-specific folder where you can deploy mod folders. I have been using the Church Expansion mod by protofan for my initial tests:
Schools\NormalSchool\Mods\GeneralChurchExpansion

This folder basically acts as another root directory for the scenario.
If the game tries to find a resource with a relative path like
Images\EventPictures\Location\Park\ParkDate.jpg
then it will first look in
Schools\NormalSchool\Mods\GeneralChurchExpansion\Images\EventPictures\Location\Park\ParkDate.jpg
and then continue to
Schools\NormalSchool\Images\EventPictures\Location\Park\ParkDate.jpg
if it does not find any in the mod directories. The same is true for all kinds of scenario-specific resources.

If the game tries to load all resources from a directory, it will load all resources from all directories (mods and base game) that match the requested directory name. If a resource shares the same relative path from its respective root directory as a resource from another mod or the base game, it will overwrite that resource and be used in place of it whenever possible.

The player can put mods into a specific load order to determine which mod may potentially override resources from another mod, as well as enabling and disabling specific mods. This is done via a new configuration panel in the main menu that you can see in the attached screenshot.

Mod authors can also add a file named ModInfo.xml to the root directory of their mod in order to provide some additional information for this configuration menu. Here an example that I made for the mod in the screenshot:

Code: [Select]
<?xml version="1.0" encoding="utf-8"?>
<ModInfo>
    <Name>General Church Expansion</Name>
    <Author>protofan</Author>
    <Description>This mod adds:

    6 new sfw events
    9 new nsfw events
    New images for the Church orgy
    171 new images in total</Description>
    <TitleImage>Images\EventPictures\Location\St. Judas Church\boobs.. I mean books.png</TitleImage>
</ModInfo>

Without this file, the mod will simply use its folder name as the mod name.

The selected mods also affect the resources that are available to the game’s development tools. So you can activate just your mod and the mods your mod depends on in order to develop new stuff for it. The mod configuration panel also has a button to check all currently active mods for errors. Events defined in the base game are ignored by this check, so it lets you get a quick idea if a specific mod might be broken, outdated or could be incompatible as a result of your load order.

I am hoping that this will make both modding and using mods easier. Maybe Lexville can even be made to run "on top" of the regular Smallville scenario and other mods won't need to make a distinction between which of the two they support.

In any case, have a Merry Christmas and a Happy New Year.
Logged
Pages: [1]   Go Up
 


anything
SimplePortal 2.3.3 © 2008-2010, SimplePortal