• Welcome to MX Bikes Official Forum. Please login or sign up.
 
April 20, 2024, 04:59:15 PM

News:

MX Bikes beta18j available! :)


Show posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Messages - JNS47

1
Documentation / Re: Dedicated server
November 02, 2022, 10:36:16 PM
Quote from: PiBoSo on July 28, 2020, 12:39:14 PM
Quote from: Paulo Rodrigues on July 22, 2020, 03:44:24 AMhm... i think if some numbers of players call me outside MXB saying the server has a anti-game player i need to do something remotely, like kick or ban.

And another question:

Will be possible (or its possible) to create server plugins with r/w commands and events?
like:

onPlayerJoined(playerObj obj, others attr...)
onPlayerRunStart(playerObj obj, others attr...)
onPlayerQuit(playerObj obj, others attr...)
...
setPlayerName() // usefull if i need to create some roles and prepend some text in the player name while he is in the server (ex: [MOD] Player name, or [VIP] Player name)
setPlayerGate(player, gateNumber) // usefull if i need to create a custom race, x1 (two bikes turn based event), sudden dead
sendPlayerToSpec(player) // usefull if i need to create a custom race, x1 (two bikes turn based event), sudden dead
sendPlayerToGate(player, gateNumber) // usefull if i need to create a custom race, x1 (two bikes turn based event), sudden dead
blockPlayerRaceEntry(all or player) //
setEvent(eventType) //
broadcastMessage(player_NotRequired, message) //
...

Thank you for the requests.
Could you please give more info about the "onPlayer" commands?
Is "two bikes turn based event" straight rhythm?
What would be the use of "blockPlayerRaceEntry"?
Please note that it's not possible to change event type while the server is running, so "setEvent" cannot be implemented.

A few years later and I'm someone else but I'd really like a server plugin interface as well.
My ideas for some interface events and functions are these (sorry, it's a lot xd):
Code (cpp) Select
#include <Windows.h>

typedef struct
{
float x;
float y;
float z;
} Vector3;

enum Shape
{
Box,
Cylinder
};

typedef struct
{
int id;
Vector3 position;
Vector3 size;
Shape shape;
unsigned long color;
} Trigger;

enum PenaltyType
{
Cutting,
JumpStart
};


// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
// Events
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

/// <summary>
/// Fired when a player is establishing a connection, before loading any resources.
/// </summary>
/// <param name="player">Pointer to players GUID.</param>
/// <param name="ipAddress">Players IP address.</param>
/// <param name="asSpectator">Whether the player tries to join as spectator.</param>
/// <returns>Whether the event should be cancelled or not.</returns>
/// <remarks>
/// Could be used to prioritize admins, block IPs, ...
/// </remarks>
bool PlayerEstablishingConnection(GUID* player, char* ipAddress, bool asSpectator);

/// <summary>
/// Fired when a player is joining the server after establishing the connection was not cancelled.
/// Starts to load resources now.
/// Player is in the player list now, so you can access a player struct through their GUID
/// This could contain the IP address, spectator state and more.
/// </summary>
/// <param name="player">Pointer to players GUID.</param>
/// <remarks>
/// Could be used to load some player related data, so it's ready once they are connected.
/// </remarks>
void PlayerJoining(GUID* player);

/// <summary>
/// Fired when a player is connected to the server and finished loading all resources (is in pits).
/// </summary>
/// <param name="player">Pointer to players GUID.</param>
/// <remarks>
/// Could be used for logging purposes or to write a welcome message saying
/// e.g.: "[PlayerX] connected from [CountryY], they have [PlaytimeZ] hours on this server.",
/// to replace their name with an alias or change their race number.
/// </remarks>
void PlayerConnected(GUID* player);

/// <summary>
/// Fired when a player is leaving the server. (directly after clicking back and accepting exiting with "OK")
/// </summary>
/// <param name="player">Pointer to players GUID.</param>
/// <remarks>
/// Could be used for logging purposes or to write a leaving message saying
/// e.g.: "[PlayerX] disconnected after [SessionTimeY] minutes".
/// </remarks>
void PlayerLeaving(GUID* player);

/// <summary>
/// Fired when player is completely disconnected from the server. All their data is getting cleaned up now.
/// </summary>
/// <param name="player">Pointer to players GUID.</param>
/// <remarks>
/// Could be used to clean up the data that about them. (free pointers, ...)
/// </remarks>
void PlayerDisconnected(GUID* player);

/// <summary>
/// Fired when player entered the track.
/// </summary>
/// <param name="player">Pointer to players GUID.</param>
void PlayerEnteredTrack(GUID* player);

/// <summary>
/// Fired when player entered pits.
/// </summary>
/// <param name="player">Pointer to players GUID.</param>
void PlayerEnteredPit(GUID* player);

/// <summary>
/// Fired when player gets a penalty.
/// </summary>
/// <param name="player">Pointer to players GUID.</param>
/// <param name="penaltyType">Type of the penalty (Cutting, JumpStart, ...).</param>
void PlayerGotPenalty(GUID* player, PenaltyType penaltyType);

/// <summary>
/// Fired when two players collide.
/// </summary>
/// <param name="playerA">Pointer to playerAs GUID.</param>
/// <param name="playerB">Pointer to playerBs GUID.</param>
void PlayerWithPlayerCollision(GUID* playerA, GUID* playerB);

/// <summary>
/// Fired when a player collides with the world.
/// </summary>
/// <param name="player">Pointer to players GUID.</param>
void PlayerWithWorldCollision(GUID* player);

/// <summary>
/// Fired when a player crashes (goes down).
/// </summary>
/// <param name="player">Pointer to players GUID.</param>
void PlayerCrash(GUID* player);

/// <summary>
/// Fired when a player starts to reset.
/// </summary>
/// <param name="player">Pointer to players GUID.</param>
/// <returns>Whether the event should be cancelled or not.</returns>
bool PlayerStartReset(GUID* player);

/// <summary>
/// Fired when a player resets (finishes to reset).
/// </summary>
/// <param name="player">Pointer to players GUID.</param>
/// <returns>Whether the event should be cancelled or not.</returns>
bool PlayerReset(GUID* player);

/// <summary>
/// Fired when a player crosses a split.
/// </summary>
/// <param name="player">Pointer to players GUID.</param>
void PlayerSplitCrossed(GUID* player);

/// <summary>
/// Fired when a player crosses the finish line (finishes a lap).
/// </summary>
/// <param name="player">Pointer to players GUID.</param>
void PlayerFinishCrossed(GUID* player);

/// <summary>
/// Fired when a player sends a message in chat (no private message).
/// Can be cancelled before sending to all players.
/// </summary>
/// <param name="player">Pointer to players GUID.</param>
/// <param name="message">the message that was sent.</param>
/// <returns>Whether the event should be cancelled or not.</returns>
bool PlayerChat(GUID* player, char* message);

/// <summary>
/// Fired when a player sends a command.
/// </summary>
/// <param name="player">Pointer to players GUID.</param>
/// <param name="command">Name of the command that was sent (first string before space).</param>
/// <param name="args">Command arguments (space seperated).</param>
/// <returns>Whether the event should be cancelled or not.</returns>
bool PlayerCommand(GUID* player, char* command, char** args);

/// <summary>
/// Fired when a player gets disqualified
/// </summary>
/// <param name="player">Pointer to disqualified players GUID.</param>
/// <param name="issuer">Pointer to GUID of player that disqualified the player.</param>
/// <param name="message">specified reason for the disqualification.</param>
/// <returns>Whether the event should be cancelled or not.</returns>
bool PlayerDisqualified(GUID* player, GUID* issuer, char* reason);

/// <summary>
/// Fired when a player gets kicked
/// </summary>
/// <param name="player">Pointer to kicked players GUID.</param>
/// <param name="issuer">Pointer to GUID of player that kicked the player.</param>
/// <param name="message">specified reason for the kick.</param>
/// <returns>Whether the event should be cancelled or not.</returns>
bool PlayerKicked(GUID* player, GUID* issuer, char* reason);

/// <summary>
/// Fired when a player gets temporarily banned
/// </summary>
/// <param name="player">Pointer to banned players GUID.</param>
/// <param name="issuer">Pointer to GUID of player that banned the player.</param>
/// <param name="seconds">Duration of the temporary ban in milliseconds.</param>
/// <param name="message">specified reason for the ban.</param>
/// <returns>Whether the event should be cancelled or not.</returns>
bool PlayerTempBanned(GUID* player, GUID* issuer, unsigned long long int milliseconds, char* reason);

/// <summary>
/// Fired when a player gets banned
/// </summary>
/// <param name="player">Pointer to banned players GUID.</param>
/// <param name="issuer">Pointer to GUID of player that banned the player.</param>
/// <param name="message">specified reason for the ban.</param>
/// <returns>Whether the event should be cancelled or not.</returns>
bool PlayerBanned(GUID* player, GUID* issuer, char* reason);

/// <summary>
/// Fired when a players spectator state changes.
/// </summary>
/// <param name="player">Pointer to players GUID.</param>
/// <param name="isSpectator">Whether the player changed to spectator. If false they changed to player.</param>
/// <returns>Whether the event should be cancelled or not.</returns>
bool PlayerSpectatorModeChanged(GUID* player, bool isSpectatorState);

/// <summary>
/// Fired when a players entered a trigger.
/// </summary>
/// <param name="player">Pointer to players GUID.</param>
/// <param name="enterPosition">Position at which the player entered the trigger.</param>
/// <param name="trigger">The trigger that was entered.</param>
/// <remarks>
/// Trigger => { int id, Vector3 position, Vector3 size, Shape shape (Box, Cylinder), unsigned long color }
/// Could be used to create minigames, e.g.: easter egg hunt. lol
/// </remarks>
void PlayerEnterTrigger(GUID* player, Vector3 enterPosition, Trigger trigger);

/// <summary>
/// Fired when a players exits a trigger.
/// </summary>
/// <param name="player">Pointer to players GUID.</param>
/// <param name="exitPosition">Position at which the player exited the trigger.</param>
/// <param name="trigger">The trigger that was exited.</param>
/// <remarks>
/// Trigger => { int id, Vector3 position, Vector3 size, Shape shape (Box, Cylinder), unsigned long color }
/// Could be used to create minigames, e.g.: easter egg hunt. lol
/// </remarks>
void PlayerExitTrigger(GUID* player, Vector3 exitPosition, Trigger trigger);

/// <summary>
/// Fired when server is about to start.
/// </summary>
/// <remarks>
/// Could be used to load data from file/database.
/// </remarks>
void ServerStarting();

/// <summary>
/// Fired when server is fully started and players can join.
/// </summary>
void ServerStarted();

/// <summary>
/// Fired when server is about to stop.
/// </summary>
/// <remarks>
/// Could be used to save some data.
/// Could maybe contain stopping reason, error code or exception as parameter.
/// </remarks>
void ServerStopping();

/// <summary>
/// Fired right before server is fully stopped.
/// </summary>
/// <remarks>
/// Could be used to log that the server stopped or clean up data (free pointers, ...).
/// Could maybe contain stopping reason, error code or exception as parameter.
/// </remarks>
void ServerStopped();

/// <summary>
/// Fired each server tick (or maybe a defined frequency).
/// </summary>
/// <remarks>
/// Can be used to send live updates.
/// </remarks>
void ServerTicked();

/// <summary>
/// Fired when the track was reset.
/// </summary>
void TrackReset();

/// <summary>
/// Fired when a session starts.
/// </summary>
/// <remarks>
/// Could be used to start own live timing.
/// </remarks>
void SessionStarted(/*session settings ((practice, qualiy or race), track, duration, ...)*/);

/// <summary>
/// Fired when a session ends.
/// </summary>
/// <remarks>
/// Could be used to stop own live timing and write results.
/// </remarks>
void SessionFinished(/*results, end reason (manually, completed, ...)*/);

/// <summary>
/// Fired when a new poll is started.
/// </summary>
/// <remarks>
/// Can be used to send live updates.
/// </remarks>
/// <returns>Whether the poll should be cancelled (doesn't go through to all players).</returns>
bool PollStarted(/*typed, id, ...*/);

/// <summary>
/// Fired when someone makes a vote for a poll.
/// </summary>
/// <param name="player">Pointer to players GUID.</param>
/// <param name="voteYes">Whether the player voted for or against it.</param>
void PollVote(GUID* player, bool voteYes);

/// <summary>
/// Fired when a poll has ended.
/// </summary>
/// <remarks>
/// Can be used to manipulate poll results.
/// </remarks>
/// <returns>Poll result.</returns>
bool PollEnded(/*type, id, votes, ...*/);


// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
// Functions
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

// Player Functions
//-----------------

// Set whether the player should be an admin or not.
void SetIsAdmin(GUID* player, bool isAdmin);

// Returns whether the player is an admin or not.
bool IsAdmin(GUID* player);

// Send a message to a specific player, that looks like a normal message.
void SendNormalMessage(GUID* player, char* message);

// Send a message to a specific player, that includes formatting options (color, bold, italic, underline, ...)
// so you can make some parts of a message stand out more.
void SendFormattedMessage(GUID* player, char* message);

// Send a private message to a specific player.
void SendPrivateMessage(GUID* player, char* message);

// Set whether the player should be a spectator or a player.
void SetIsSpectator(GUID* player, bool isSpectator);

// Returns whether the player is a spectator or not.
bool IsSpectator(GUID* player);

// Disqualify a player, optionally with a reason and an issuer (issuer = nullptr -> server)
// reason and issuer could be added as comment in .ini file, else just being used for the event.
void Disqualify(GUID* player, char* reason = nullptr, GUID* issuer = nullptr);

// Kick a player, optionally with a reason and an issuer (issuer = nullptr -> server)
// reason and issuer could be added as comment in .ini file, else just being used for the event.
void Kick(GUID* player, char* reason = nullptr, GUID* issuer = nullptr);

// TempBan a player for a given time, optionally with a reason and an issuer (issuer = nullptr -> server)
// reason and issuer could be added as comment in .ini file, else just being used for the event.
void TempBan(GUID* player, unsigned long long int milliseconds, char* reason = nullptr, GUID* issuer = nullptr);

// Ban a player, optionally with a reason and an issuer (issuer = nullptr -> server)
// reason and issuer could be added as comment in .ini file, else just being used for the event.
void Ban(GUID* player, char* reason = nullptr, GUID* issuer = nullptr);

// Whitelist a player, optionally with an issuer (issuer = nullptr -> server)
// issuer could be added as comment in .ini file.
void Whitelist(GUID* player, char* reason = nullptr, GUID* issuer = nullptr);

// Blacklist a player, optionally with an issuer (issuer = nullptr -> server)
// issuer could be added as comment in .ini file.
void Blacklist(GUID* player, GUID* issuer = nullptr);

// Create a player specific trigger.
// Trigger => { int id, Vector3 position, Vector3 size, Shape shape (Box, Cylinder), unsigned long color }
void AddTrigger(GUID* player, Trigger trigger);

// Remove a player specific trigger.
// Trigger => { int id, Vector3 position, Vector3 size, Shape shape (Box, Cylinder), unsigned long color }
void DeleteTrigger(GUID* player, Trigger trigger);

// Get the position of a player (maybe also add yaw, pitch, ...).
Vector3 GetPosition(GUID* player);

// Set the position of a player (maybe also add yaw, pitch, ...).
void SetPosition(GUID* player, Vector3, double, double);

// Get the username of a player (full name).
char* GetName(GUID* player);

// Get the alias of a player (if no alias set, use username).
// Used to replace username.
char* GetAlias(GUID* player);

// Set an alias for a player.
void SetAlias(GUID* player, char* alias);

// Get the rider number of a player.
unsigned short int GetRiderNumber(GUID* player);

// Set a rider number for a player.
void SetRiderNumber(GUID* player, unsigned short int number);

// Get the rider name of a player (name on jersey and bike).
char* GetRiderName(GUID* player);

// Set the rider name of a player (name on jersey and bike).
void SetRiderName(GUID* player, char* name);

// Get the start position of a player (on which gate a player is starting).
int GetStartPosition(GUID* player);

// Set the start position of a player (on which gate a player is starting).
void SetStartPosition(GUID* player, int position);

// Pass to a specific player client, to draw elements.
// allows server HUD, might get abused though. Would still be cool though.
void Draw(GUID* player, int _iState, int* _piNumQuads, void** _ppQuad, int* _piNumString, void** _ppString);

// Server Functions
//-----------------

// Pass to all clients, to draw elements.
// allows server HUD, might get abused though. Would still be cool though.
void Draw(int _iState, int* _piNumQuads, void** _ppQuad, int* _piNumString, void** _ppString);

// Send a message to all players.
void SendNormalMessage(char* message);

// Send a message to all players, that includes formatting options (color, bold, italic, underline, ...)
// so you can make some parts of a message stand out more.
void SendFormattedMessage(char* message);

// Start a specific session.
void StartSession(/*Session info (race1, race2, qualy, ...), maybe track, duration and other settings*/);

// Reset track.
void ResetTrack();

// Stop server.
void Stop();

// Create a trigger for all players.
// Trigger => { int id, Vector3 position, Vector3 size, Shape shape (Box, Cylinder), unsigned long color }
void AddTrigger(Trigger trigger);

// Remove a trigger for all players.
// Trigger => { int id, Vector3 position, Vector3 size, Shape shape (Box, Cylinder), unsigned long color }
void DeleteTrigger(Trigger trigger);


// Also:
//
// Some way to (un-)register custom commands.
//
// Getters (and setters where useful) for the other structs used for output plugins as well.
// (SPluginsBikeEvent_t, SPluginsBikeData_t, SPluginsBikeLap_t, SPluginsRaceTrackPosition_t, ...)
// (or some similar structs that have the information about the server/game state)
Tried to make it clear what all of this would be for with the comments.

I'm not that much of a C(++) dev, so implementation wise it might be shit and yours would probably differ a lot.
It's more about the idea of the functions/events and the comments of them. Just take it as a big wishlist (it's christmas in ~2 months 👉👈🥺 😂) of stuff with which I could probably do most stuff. Just some of it would be cool already.

I know that some of that stuff is already possible with UDP sockets but having an option inside the server itself would be nice as well. And I also know that some of that stuff would probably require new features to be added (e.g.: temporary bans, message formatting).

Feel free to reach out if there's something you don't understand the purpose of. 😅
2
Tracks / Re: Fmx tracks
June 10, 2020, 01:14:51 AM
https://mxb-mods.com/uploads/all/tracks/tracks_freeride/
you can find another FMX track there, haven't tested it though.
3
No problems with opening the yz for me, GIMP version 2.10.14. No problems with the tm either, with which I had the error before.
4
So here's part 2. It's a lot and it's kind of a mess, since I've spent so much time with some parts of it and wanted to get it posted finally, so some parts are more detailed than others.
The order doesn't have any background.

2. UI
No, I'm not asking for a prettier UI, I want to create a pretty UI myself.

2.1. Image scaling
Problem
At the moment you have to do all the calculation yourself when creating UIs, which includes images. This can be a problem, with different screen resolutions, if the image isn't big enough.

Solution
It would be cool to be able to have a fixed box-size for the image, but being able to change whether the image should be stretched to fit the box, or being kept as it is. (CSS contain and cover)
But this would need two more options to work properly:
keeping the aspect ratio of the image or changing it to fit the box
where to position the image (for both axis, horizontal and vertical: start, center, end)

2.2. More units for position and size
Problem
The only way of setting size and position of an ui element at the moment is to set the percentage of the space it takes of the axis, that's a problem when creating a square for example. You can't just set the same percentage to width and height because it's relative to the axis, which differs if you don't have a 1:1 aspect ratio.

Solution
More units. Again, I'm referring to CSS where you have
  • vh (view height - percentage relative to the height)
  • vw (view width - percentage relative to the width)
  • vmin (percentage relative to the smaller axis)
  • vmax (percentage relative to the bigger axis)
  • % (percentage relative to the containers same axis you change the value for)
But I'd also add something like
  • %w (percentage relative to the container width)
  • %h (percentage relative to the container height)
as relative units and
  • px (pixels)
as absolute unit.

Sure, there are even more, but those are probably the more important ones (ignoring font related ones like "em" and "rem").

Why absolute units? (pixels)
For example as padding or a border you sometimes want a absolute width no matter what resolution you are on, or if you want a image to be it's full size but not being stretched (because of quality loss) you could just set it's width and height to the original images size.
I know that's covered with image-scaling, but it's just an example.

2.3. maths
Why?
For example to define a start-position to something like
((3*buttonWidth)+(4*borderWidth))

What?
  • (+) addition
  • (-) subtraction
  • (*) multiplication
  • (/) division
  • (%) modulo? lol
  • (round) rounding value x to n decimals

2.4. min-width/height, max-width/height
Why?
Having definitions like
width = 10%
min-width = 100px
max-width = 300px
so the element is set to a width of 10%, but if 10% is less than 100px it's set to 100px. If it's more than 300px, it's set to 300px.

2.5. Something similar to CSS media queries (adaptive design instead of responsive)
Why?
If someone is playing on a different aspect-ratio than 16:9 you might want to layout the UI differently, which isn't as easy atm.

What?
CSS has media queries which allow you to change styles depending on (min/max)aspect-ratio, (min/max)width/height, orientation (if someone is playing 9:16, lol), resolution (something like pixels per inch) and a lot more. But those are probably the only needed ones. (at least aspect-ratio and width/height)

2.6. positioning
What?
  • Instead of (or in addition to) start- and end-positions there should be start-positions and width/height
  • Padding and margin would be pretty neat as well
  • Positioning relative to sibling elements
    positionX = ElementID.positionX + ElementID.width + 10px

Why?
width/height instead of end-positions is a must-have to reduce calculation while creating UIs.

margin might not be pretty important since you can just change position and width/height, but padding would be useful for images and text inside of containers to prevent those reaching the border of the element.

positioning relative to sibling elements could be useful when sizes change and aren't static all the time. (which would be nice)

2.7. Events and Functions for UI elements
Problem
We are pretty limited in what buttons and stuff do, we just set a id to the element and that's it. No way (None I know about at least) to bind custom functions to a button.

Solution
Instead of setting a ID to give a element a function, there could be a few events in which you can call a function or create a own one.

Event examples:
onClick
onMouseEnter
onMouseLeave
onMouseHover
onSelect(item)
For Checkboxes, Dropdowns and similar stuff
onCheck
onSelect
...

Function examples:
OpenUI(uiID)
  Testing
  Race
  Replay
  Garage
...
AddClass(ElementID, Class)
RemoveClass(ElementID, Class)
ChangeLanguage(language)
SetBikePaint(PaintID)
Exit()
ExportResult()

If we could rewrite some functions like the race result export function, it would be pretty neat.

2.8. invisible elements
I guess I don't have to explain that, just adding a style option to make a element invisible, so you can toggle the visibility without having to re-create the element.

2.9. change background
What?
It would be cool if you had the option to change the menu background (where you see your bike) to different predefined scenes (or could even create own ones).
I don't know how the background really works, but having some small maps where you can see your bike in different poses would be cool.
For example a map with just a small jump with your bike whipping (and the rider on it of course) and being able to see it from every side (like you can rotate the camera in the current background with the bike stand). Or one shredding some whoops, one with the rider just sitting on the bike, or whatever.
The bike could be dirtier in some scenes as well, so you can see your bike in race conditions.

The standard bike stand scene shouldn't be replaced of course, it should just be additional scenes you can choose.
Speaking of the bike stand scene, it would be nice, being able to turn off the rider, so just the bike is visible.

Why?
It's just a visual improvement, not necessary, but cool.

And I know it's possible to change the background already and I think it's working through maps (not sure though) but afaik it's not possible to change the pose of the rider and the bike to something else than the bike stand.

2.10. change and create elements on events
Referring to Events and Functions for UI elements I'd like to be able to change and create elements on these events. This would make the UI files a lot more readable as well. afaik changing elements on hover and click is done by naming for example the color "color2" and "color3". That's no clear naming, instead I'd suggest Json similar syntax which I'll talk about later.

2.11. elements focusable (controller support)
I explained that in my first post already, where I talked about binding. You should be able to add a line like "focusable" on UI elements and then have a bindable function to iterate through all the elements with the "focusable" line ("next focusable element", "previous focusable element") in the order they are defined.

2.12. more changeable UIs and HUD / own UI pages/HUD elements
for example:
  • chat
  • gear
  • pitboard

yes, you can change gear a bit already and the pitboard as well. But it's always the same format, I'd like to be able to do stuff like writing my time in a circle or right to left, whatever. Even if it's dumb.

So it would be nice if you just had variables which you could use in EVERY UI file.
Variables like "profiles[]", "profiles[].name", "activeProfileID", "currentBike", "currentBikePaint", ... Just everything we can see in the UI.
There are also a lot of variables which are available in plugins, using them in the UI language might be cool as well.

2.13. videos
It would be a nice addition to have videos just like bitmaps. For example as a background.

2.14. Polygons, ellipses and lines
Don't have to see a lot about that either, but it should be possible to not use the whole ellipse but cut out a rectangle or triangle out of the ellipse.
Lines should be possible to make tilted as well.

2.15. use variables and classes (for text, color, ...)
variables should be a value which can be stored, changed and used. Like saving "10px" as width, or saving the string "test" to insert as content.
classes should be a few styles which can all be applied to multiple elements. Styles defined in the element itself should overwrite class-styles.
Example:
className = {
  width = 10px;
  height = 30px;
  color = #00ff00;
}
A nice addition would be to use values from another element (I mentioned that as relative positioning), like "elementID.color"

2.16. display steam group tag in front of name
So you don't have to put your team name in your steam name and the tag is limited to users who are in the group.

2.17. add nation to display
I've read that suggestion somewhere else, I'd like it a lot.

2.18. separate stuff (manufacturer, kit, ...)
I think it would be useful to provide separated manufacturer, model and color variables for kits, helmets, boots, bikes, ... so you could add multiple dropdowns for it.
(bike - manufacturer: MSM, model: 450xf, color = paint)
(boots - manufacturer: Alpinestars, model: tech10, color: black)

I know, not everybody might like that, that's why I said just providing variables for it.

2.19. reload button in bike selection
So there is no need to switch to another paint and back to the changed one again while creating a paint.
Possible to achieve ourselves if we'd get the possibility to have functions.

2.20. search function (tracks, bikes, paints)
Again, through functions and using variables from an input field we'd be able to do this ourselves.

2.21. using everything everywhere
Instead of having predefined buttons for a page it would be better being able to use everything everywhere. Goes with the "bike+rider inspect view thing" as well. (Using it on every menu screen if you wish)
I'd also like to have this view just as a element, so it's downscaled to the size and doesn't contain the whole screen.

2.22 conditional styles
style being dependable on variables. Like making the text red if the string contains "Honda", or underline the track name, if you don't have it installed.

2.23. defining elements
I'd suggest to remove the button element or change it so it's more unique. But I think every element should have the options a button has.
Indeed I think we need just a few elements and have the real stuff that's changing it inside of it.
Like every element should have a name, position and size (always a rectangle) for sure, but also optional things like background (for a background-color), events (onClick, onHover) and content (to make it a container). So pretty much like a HTML div (sure, other HTML elements can do this too, but divs are most commonly used), which can be almost everything with the right CSS and JS.
A container can then either have more elements, a shape (another rectangle, a line, a polygon or a circle, which then has either a fixed color or a sprite to draw), text or a tooltip.

Would be perfect if it was possible to create own elements which consist out of another (or multiple) elements and just has own defined variables to change. I'll use this on the syntax example under "readability".

stackable containers
not sure, if already possible, there are "button"s inside of "item_button"s, but I guess you can't stack it deeper.

change children on parent-elements events (onClick, ...)
If I had a container which acts as a button I'd like to change all the children elements on a onClick event sent by the container. (for example changing the color of each children)

2.24. better display of server missing mods
I think just a "*" isn't the best way of marking a track as missing, so coloring it or something like this could be better. (or a variable "hasModInstalled" --> see conditional styles)

2.25. readability
do onHover, onClick, ... instead of sprite1, sprite2, ...
example:
  • onClick = {sprite()}
  • onHover = {sound()}
  • onClick = {
       hide(ELEMENT_ID);
       joinServer(ServerInfos);
    }

json like syntax
here (pastebin) is an example, I just came up with. It's a lot more lines than the current language, but a lot comes from brackets through deep containers. And a lot of it could be shortened by using element templates (if added), but I wanted to show more of the stuff I mentioned.
And I think it's a bit better readable. Especially if you had syntax highlighting for it.
There might be some things there, I didn't mention here, but no very important ones.
I'm not 100% sure if this would be a usable UI, since I haven't tested it (I mean, I have no way to test it currently) but I think it's kinda realistic stuff.

Maybe my syntax sucks, it's just my thought, not a must.

2.26. instead of changing the UI language replace it with HTML/CSS


I know that's a lot, if some stuff is planned to implement, I'd be glad to help, for example with writing a parser for all the UI language stuff (If the language is changed. I'm by far not as good with C/C++ as with C#, JS,... but if wished I'd try), or just something else. But I know it's unlikely you hook up a random guy helping with your code. :D

-Jonas
5
seems like it's not just a visual thing.
My elements are like this:
item_button
{
  name id_testing
  button
  {
   rect 0.100000 0.250000 0.300000 0.750000
   sprite1 test_image.tga
   sprite2 test_image_hover.tga
   sprite3 test_image_hover.tga
   sample1 ui_button_over.wav
   sample2 ui_button_click.wav
  }
  textid Testing
  text
  {
   font main.fnt
   pos 0.006250 0.000000
   fontsize 0.044444
   align right
  }
  color1 255 240 240 240
  color2 255 240 240 240
  color3 255 240 240 240
}
item_button
{
  name ID_MULTIPLAYER
  button
  {
   rect 0.300000 0.250000 0.500000 0.750000
   sprite1 test_image.tga
   sprite2 test_image_hover.tga
   sprite3 test_image_hover.tga
   sample1 ui_button_over.wav
   sample2 ui_button_click.wav
  }
  textid Single_race
  text
  {
   font main.fnt
   pos 0.006250 0.000000
   fontsize 0.044444
   align right
  }
  color1 255 240 240 240
  color2 255 240 240 240
  color3 255 240 240 240
}
item_button
{
  name ID_BIKE
  button
  {
   rect 0.500000 0.250000 0.700000 0.750000
   sprite1 test_image.tga
   sprite2 test_image_hover.tga
   sprite3 test_image_hover.tga
   sample1 ui_button_over.wav
   sample2 ui_button_click.wav
  }
  textid bike_selection
  text
  {
   font main.fnt
   pos 0.006250 0.000000
   fontsize 0.044444
   align right
  }
  color1 255 240 240 240
  color2 255 240 240 240
  color3 255 240 240 240
}
as you can see, the first one ends on x=0.300000, the next one starts on x=0.300000 so there shouldn't be a gap. But there is one, and the gap is a gray pixel, even though my background is white. So there is a real border around buttons and bitmaps.

In the attachments you can see a test with the main2.tga and main3.tga which is used in the default UI and if I put my cursor right in the middle of those two elements none of those is considered hovered over.
Might not be a problem for the default UI, but it is one for what I'm trying to do.
6
Bug Reports / UI creates border around bitmaps
May 11, 2020, 03:58:59 AM
I want to create a main menu UI, but somehow there is a border drawn around bitmaps (and sprites in buttons). Maybe you don't see it easily on the screenshot, so you might have to zoom.
20200511032501_1.jpg
borders of my images are #ffffff, so it can't be the image which causes it I guess.

tried to make borders transparent, the gray border goes away if I do this, but this makes it a lot harder to get a nice transition from the images to white as you can see here (the three colored images have a transparent border)
20200511033230_1.jpg
7
Other / Re: JNS47's Bike Fonts
May 10, 2020, 03:56:11 PM
You should download one font and look at the files it has, makes it pretty much clear.

But I'll try to explain:
First of all you create a tga file with all the digits in the same image in one row. (0123456789) Every digit has to have the same width (so, if your image is 800px in width, every digits has a width of 80px). You shouldn't go too big, I'd recommend a height between 100px and max 160px, so it fits on the bike. Every digit should have ~2 free pixels on the left and the right, don't go too big on the gap as well.
(if every digit has 80px, you have ~2 free pixels on the left, 76px for your digit and ~2 free pixels on the right)

Then you create a folder for your font, you should use "_" instead of " ". In this folder you create a "<your_folder_name>.ini" with following content:
[info]
name = <font name ingame, can have whitespaces>

[data]
code = 0

Then create another file in this folder called "gfx.cfg", content (remove the "//" and the comments behind it in every row):
chassis_number //thats the sideplates
{
font = <file_name>.tga
fontstring = 0123456789
spacing = 70 //the width every digit has (your image width / 10)
posx = 60 //where to position the digits on the sideplates, x-coordinate
posy = 11 //where to position the digits on the sideplates, y-coordinate
}
steer_number //thats the frontplate
{
font = <file_name>.tga
fontstring = 0123456789
spacing = 70 //the width every digit has (your image width / 10)
posx = 30 //where to position the digits on the sideplates, x-coordinate
posy = 13 //where to position the digits on the sideplates, y-coordinate
}
You have to figure out, which positions and spacing fits your font.

Lastly drag your .tga file into the folder and move the folder into "<MX Bikes directory with .exe in it>/misc/fonts/", create misc and font folders if they are missing.

Open up your game and select the font, hf.
8
Other / Re: JNS47's Bike Fonts
May 10, 2020, 03:19:42 PM
<3
9
Other / JNS47's Bike Fonts
May 10, 2020, 06:09:38 AM
I've created some bike fonts.

overview.png
first row are the shadow-black fonts in their various colors.
second row are the double-bordered-white, double-bordered-black, bordered-white, bordered-black, default-black and default-white fonts in this order.
third row are the shadow-white fonts in their various colors.

All the fonts are available in black and white and have a one-digit version (which is a bit bigger) and a two-digit version (3 digits are also possible in most cases, but it doesn't look perfect)
On some bikes the one-digit version even looks fine with more digits, but not on every bike. So go test it for yourself.

If you want to download the full pack, you can get it here:
Download all

if you want to download fonts separately (because it's 52 fonts in total, which is quite a bit scrolling), you can get it here:
Separate fonts

High-Res tga and png (feel free to use) files and some more images which I didn't want to post here because of their size are in the root folder here
(thanks to iNsane for making this nice background I used to make those screenshots there)

Sadly on the Yamaha the fonts act kinda weird, nothing I can do about it without shrinking the font, which I don't want to.
Let me know if you get any problems with downloading, installation or the fonts in general.

hf.
-Jonas

If anybody wants to make a Kit Font in the same style, go for it (I can provide you with my gimp project file if it helps, lol), I won't do it myself because it's just too much work adding 26 more characters of every style, even if they are pretty similar.
10
Other / Re: 16 Segment Pitboard
May 07, 2020, 11:10:37 PM
Thanks for your thanks! lol
11
Other / 16 Segment Pitboard
May 07, 2020, 04:01:36 AM
A 16 segment pitboard.
pitboard.png

16seg.jpg

DOWNLOAD
12
Thanks everyone who helped in any way!
13
Track Editing / Re: Long reset BUG?
April 16, 2020, 03:50:30 AM
Don't know anything about track editing, and if I understood the problem correctly.

But I think I had something like this on MXB Club a few times already. When I resetted in the rollers section I got resetted to the last jump before the finish line.
But I think it was just the first time after going on the track, once I ran a lap it didn't happen. (just had this with testing, not in a race)

So if it's the same problem, it could be just a bug and nothing wrong with your track.
14
This thread will be updated with further suggestions, to prevent spam
(I have a lot of suggestions, just not written in full words yet. And you'll probably hate me, because most of my suggestions would be a hell lot of work to implement)

1. Binding
Today when I wanted to watch a replay I realized all those replay actions like play/pause, fast forward, ... are now binded to the numpad. The problem with this is, in b13 default binding of rotating and changing FOV in replay were bound to the numpad. So now when I want to rotate it jumps to the next/previous frame at the same time and there is no way (I think) to unbind the replay actions. It's possible however to rebind rotating and changing FOV, so I tried that. When I bound it to another button, it worked fine but I preferred having those on the numpad, so I wanted to bind it there again. Next problem: You can't bind it to the numpad anymore after changing.

So the first suggestion is to make EVERYTHING (un)bindable and add it to the settings.

But I wouldn't create a thread just to mention this, in my opinion binding needs to be reworked.
Besides all the binds in the settings there is a "control.txt" file in our profile directory but it's a pain just looking at it. You'd argue we don't need to change anything in there, if it can be done ingame.
But is that a valid argument to have ugly config files? (It's not just the controls.txt, some other config files could use a rework as well. No offense.)
And some people might really need to change something in there, for some advanced configuration which can't be done ingame. (for example changing replay rotation back to numpad keys)

My second suggestion isn't polishing the controls.txt however, but rethinking the binding concept first.
At the moment it seems like keys are bound to actions (maybe it's not implemented that way, and it just looks like in the controls.txt) but I think it's smarter to bind actions to keys.
What I mean:
a line of the controls file looks like this atm:
CTRL_CHANGEVIEW KEY 46 0.000000 0.000000 0.000000 0 10.000000 10.000000 0 1.000000 0.000000 0.000000This way it looks like it's saying "the action ("CTRL_CHANGEVIEW") can be activated with the key (46 -> 'C' on the keyboard. Don't know why tbh, since ASCII value of 'C' is 67)"
but it's better to say "the key (46) will activate the action ("CTRL_CHANGEVIEW")".

Why? Doesn't sound like a useful change, doesn't even sound like it'd change anything, right?
But there are some things which are done cleaner if the "binding a action to an key"-way is chosen in my opinion.

The first thing is having multiple keys doing the same thing.
Here's an example done in both ways, I want to bind the throttle to my XBOX Controllers RT but I want to be able to use my 'W' key on the keyboard for the throttle as well. I'll change the syntax a bit (similar to csgo's bind commands).
Action bound to key:
bind XBOX360_RT "throttle"
bind W "throttle"
Key bound to action:
bind "throttle" XBOX360_RT
bind "throttle" W
as you can see, there is two lines starting with "bind "throttle"". That's a problem if you don't read the whole file explicit but just search for the first entry of "throttle". Sure, with the action --> key-way, you have to read the whole file as well but it makes sense to do there.

Next is binding with arguments. Currently there is no changeable bind with arguments, but the autochat uses arguments (probably it does... I mean... It has to). Thats just a stylistic thing to have everything organized.
bind 1 "autochat 'gg wp'" is better than
bind autochat 1 "gg wp" because it has the action right in front of it's argument instead of having the key between those.

Lastly, where the current way of binding key to actions looks probably cleaner: Binding multiple actions to one key.
You'd just have two separate lines like this:
bind "clutch" Y
bind "shiftUp" Y
But as csgo shows you can have multiple actions on one key with the other way as well:
bind Y "clutch; shiftUp"
You can then easily separate those actions by splitting the string inside the " on semicolons.

Yes, there was a thread already suggesting multiple actions with one key and it was rejected, but I think it's a pretty useful feature even if you can't think of a use case, someone will find one for sure.
Idk, maybe having a button for moving in replay mode and decreasing speed to X before. (If there was the possibility of binding a button to set a specific speed instead of decreasing with every click)


With that aside I can talk about the syntax of the controls.txt. I guess nobody will deny it's not very readable. I mentioned csgo before and they do a pretty good job in binding I think, in this guide you can see it.
Normal binds, toggling, increment, ... they have it all.
Those binds are just console commands which are stored in a file, this file is loaded on startup.

I've created an example syntax, it's mostly similar to JSON:
InputDevices: [
Keyboard1: {
ID: ?,
AnalogKeys: {}
},
Gamepad1: {
ID: ?,
AnalogKeys: {
RT: {
deadZone: ?,
...
},
RStickX_Negative: {
...
},
RStickX_Positive: {
...
}
}
}
],
AnalogActions: [
throttle: {
linearity: ?,
...
},
rotate_left: {
...
},
rotate_right: {
...
}
],
General: [
? ? "vr_reset"
],
Menu: [
// = click (just activate for one tick), UPARROW, DOWNARROW instead of Keycodes for readability
Keyboard1 UPARROW "focus_previous",
Keyboard1 DOWNARROW "focus_next",
...
],
OnTrack: [
// ~ = analog input
Gamepad1 RT "~throttle",
// + = key down (keep active as long as key is down)
Gamepad1 Y "+clutch;shift_up",
// '\' for escaping the ' " '
Keyboard1 G "chat \"gg\"",
...
],
Replay: [
Gamepad1 RStickX_Negative "~rotate_left",
Gamepad1 RStickX_Positive "~rotate_right",
...
]
I guess most of it is pretty clear, at least with the comments. You have different bindings for being on track than in replay, ...
But why do I have deadZone bound to the key but linearity (some other settings should be there as well) bound to the action?
Well, you most likely have a dead zone because of your controller not being perfectly centered, so such stuff should be bound to the key/stick/trigger.
But if you had linearity there as well, you wouldn't have as much control. For example if you'd have front brake and rear brake on the same button, (yeah, there is a setting for combined breaks, but still you could do this.) you don't want to brake the same amount on both of them, so they need their own setting, not the keys one.

Probably would be overkill to have linearity and such for every action AND every key separated. (if I bind throttle to "W" I want it to have a linearity of 100%, on "E" I want a linearity of 80%)

I was talking about csgo having commands for binds, well... In csgo there is actually everything a command which can be used in console. ("+forward" for moving forward, "disconnect" to go back to main menu, "connect 127.0.0.1" to connect to a server, ...) So you can bind EVERYTHING if you wish, even connecting to a specific server. I think thats pretty cool, perfect if those commands could be bound to UI, (but a lot of work) but thats gonna be another suggestion I'll once post.

Oh, maybe you've seen "focus_next" and "focus_previous" in my syntax example. My thought on this is having a boolean of "focusable" on every UI Element and with "focus_next" you jump to the next UI element (mouse over/hover) which has "focusable = true" and is visible. with a bind of "element_click" you could fulfill the possibility of Controller support in the UI.


Alright, that's it for now, thanks for reading!
-Jonas

(Hope I made it clear what I mean, there might be some misunderstanding, english isn't my native language. Feel free to ask.)
15
General Discussion / Re: MX Bikes beta14
April 08, 2020, 04:11:16 PM
Date on records at the statistics page seems to be off by half an hour for me, just did a lap a few minutes ago (~4pm CET) but it says 3:30 pm (CET).
http://stats.mx-bikes.com/records.php?trackid=25&bikeid=1 if you want to see it yourself.

Just a small thing, but I think it should be correct anyways. Thanks for the update btw.! <3