Code Monkey home page Code Monkey logo

libultraship's People

Contributors

aloxado320 avatar alto1772 avatar amannus avatar archez avatar baoulettes avatar briaguya-ai avatar dcvz avatar emill avatar garrettjoecox avatar garyodernichts avatar greatargorath avatar jbodner09 avatar kenix3 avatar kiritodv avatar leggettc18 avatar lildavid avatar louist103 avatar malkierian avatar melonspeedruns avatar nestelami avatar qurious-pixel avatar random06457 avatar rozelette avatar sheepytina avatar sirius902 avatar spodi avatar stratomaster64 avatar th-2021 avatar vaguerant avatar vanfanel avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

libultraship's Issues

rename stick/button stick macros/vars

right now we have

#define BTN_STICKLEFT 0x10000
#define BTN_STICKRIGHT 0x20000
#define BTN_STICKDOWN 0x40000
#define BTN_STICKUP 0x80000
#define BTN_VSTICKUP 0x100000
#define BTN_VSTICKDOWN 0x200000
#define BTN_VSTICKLEFT 0x400000
#define BTN_VSTICKRIGHT 0x800000

it's not clear what VSTICK means, and on the analog side of things we have

/* 0x02 */ int8_t stick_x;
/* 0x03 */ int8_t stick_y;

/* 0x1C */ int8_t right_stick_x;
/* 0x20 */ int8_t right_stick_y;

i think it would make sense to switch these to be

 #define BTN_LSTICKLEFT 0x10000 
 #define BTN_LSTICKRIGHT 0x20000 
 #define BTN_LSTICKDOWN 0x40000 
 #define BTN_LSTICKUP 0x80000 
 #define BTN_RSTICKUP 0x100000 
 #define BTN_RSTICKDOWN 0x200000 
 #define BTN_RSTICKLEFT 0x400000 
 #define BTN_RSTICKRIGHT 0x800000 

and

 /* 0x02 */ int8_t left_stick_x; 
 /* 0x03 */ int8_t left_stick_y; 

deadzone math

i would like to allow users to set a deadzone with a unit that means something. the current deadzone is just a number with no context. i think it would be ideal to have this number be a percentage, with 100% meaning no inputs from the stick are counted because 100% of the stick range is included in the deadzone.

if SDL always reported a value that fit within a circle this wouldn't be a problem. sqrt(x^2 + x^2) would be at max MAX_AXIS_RANGE and we could just have the user set a percentage of MAX_AXIS_RANGE, but we can't count on that being the case.

in my testing on an xbox controller (with a circular gate on the analog stick), i've been able to get normalized values (MAX_AXIS_RANGE/MAX_SDL_RANGE), that give a radius of closer to 90 (as opposed to 85) (~64 and ~63 for x and y respectively)

for #350 i'm going to go ahead and just do a percentage of MAX_AXIS_RANGE, as that still feels better than what we have now

image

tl;dr

try setting the deadzone in the current controller config window somewhere between 85 and 95 and look at the input preview, you'll see the oddities

Discovery: Controller mapping/configuration UX

Motivation/User Stories

  • As a player of a ports using LUS, I should be able to map/configure my controller(s) intuitively.
  • As a developer of a port using LUS, I should be able to provide a tailored controller mapping/configuration experience for players.
  • As a developer of a port using LUS, I should be able to get up and running without building my own controller mapping/configuration menu.

Definitions

  • "I should be able to map/configure my controller(s) intuitively."

    • For the LUS provided menu, following best practices used by emulators makes sense. Mapping from button/axis on a physical device to N64 button/axis using language related to N64 buttons/axes provides all the functionality a port will need to get up and running. "Intuitive," in this case, means "intuitive to people familiar with the original game controls on N64 and familiar with controller mapping patterns used by emulators.
      • I believe the LUS provided menu should focus on functionality first and foremost. Having the answer to "how do i do x?" be, "you can't" is about as unintuitive as it gets.
      • It might make sense to separate basic/advanced settings as more functionality is added.
    • For port provided menus this is more complex. Ideally a port would follow best practices used by gamepad focused PC games, likely providing a mapping from button to action.
      • LUS may need to provide "extended" controller functionality for this, as ports may want to allow players to use different buttons for menus vs gameplay (for example in SoH, B for sword being mapped to xbox X, B for going back on file select menu being mapped to xbox B)
  • "I should be able to get up and running without building my own controller mapping/configuration menu"

    • To provide this, LUS should have a pretty good out of the box menu
    • It might be helpful to provide some basic customization options, such as "how many controller ports should be shown" or "do you need additional axes for right stick/gyro"

Discovery

"Out of the box"

  • What emulators provide the best controller mapping/configuration UX?
  • What controller mapping/configuration features are missing from LUS?

"Custom"

  • What PC games provide the best controller mapping/configuration UX?

Input editor preview and gyro calibration don't work as expected

The issue comes from a fix on the ControlDeck, when the InputEditor is open or any other view, the game stops reading data from the controllers, because of that the stick preview and the gyro calibration don't work, as a few other bugs related to this.

This patch should fix it, its tested on both pc and switch

Input Fix Patch

Demo:

2023-01-25.17-04-39.mp4

Timer precision issues

int64_t left = next - qpc_to_100ns(t.QuadPart);
if (left > 0) {
LARGE_INTEGER li;
li.QuadPart = -left;

I would like to point out that the Windows scheduler cannot actually do 100 ns on a wait, even at the highest possible timer resolution :)

For proper framepacing, you should adopt something more conservative:

 Timer = Deadline - 1 ms
 Busy-wait the remaining time, checking QPC and calling YieldProcessor (...).

I know this sounds inefficient, but in fact it is not.

The amount of time that you'll spend busy-waiting because the next frame deadline is less than 1 ms is probably 10-20% of your total wait time at 60 FPS. And you'll never -miss- a frame, unlike the current design that's constantly going to return after the frame deadline (because, again, 100 ns scheduling is ridiculous).

Class copy constructors/operators should be correct

Any class that has a destructor also has a copy assignment operator and copy constructor.
Evaluate any class with a pointer (like Window and SDLController) or shared_ptr for copy assignment/constructor.

Bongo Bongo fist attack

SoH version: Spock Charlie 7.0.2

If you dodge bongo bongo's fist attack the hand doesnt come back and its just stay stuck in that state.
i later did some testing and it seems like this occurs if no clip is enabled

bongobongo.mp4

Feature: Ability to clear/remove Cvar

We already have the ability to register/get/set Cvars but nothing for removing/clearing cvars. This would be useful for a number of reasons, and should remove the key/value from the underlying JSON

Project License

In order to affirm the project license after moving this project from https://github.com/HarbourMasters/Shipwright to the repository at https://github.com/kenix3/libultraship, we need to ask everyone to affirm the license in the repository.

Please comment affirming you agree, and are able, to having your prior contributions licensed under the terms described the license in this repository.

We're largely asking this because the move constituted leaving the subrepo. The GitHub ToS is not perfectly clear how licenses apply to subrepos, so to be safe we are asking for an affirmation. Beyond that, we also changed the copyright line in the license file as "Harbour Masters" does not currently exist as a legal entity. Thankyou.

@Kenix3 @NEstelami @KiritoDv @dcvz @louist103 @Emill @briaguya-ai @leggettc18 @Rozelette @garrettjoecox @GaryOderNichts @Sirius902 @aMannus @Baoulettes @lilDavid @MelonSpeedruns @jbodner09 @PurpleHato @GreatArgorath @qurious-pixel @vaguerant @earthcrafterman @Random06457 @AloXado320 @th-2021 @JoshDuMan @Alto1772 @Archez @Sarge-117 @crowell @sholdee @m4xw @JakeEdvenson @Nycz-lab @InfoManiac742 @guaycuru @modestposer @Stormghetti @Dog @ChristopherJTrent @agamache @TheLegendOfLame @andrewwvc @ProjectRevoTPP @sparklingshampoo @MaikelChan @kev4cards

License libultraship Fast3D fork as MIT

While auditing the code for libultraship I noticed we have an older version of the Fast3D license. After thinking it through, I think the libultraship fork of Fast3D would be better served with the MIT license than the new Fast3D license. I have already talked this over with @Emill, and he is good with the change.

Two different groups of people are getting pinged for this new license: libultraship contributors and Fast3D contributors.

To the libultraship contributors: Your contributions are under the current license on the LUS Fast3D fork. This license does not work for projects that will want to use libultraship. We need at least the newest Fast3D license, but MIT matches the rest of libultraship and thus makes sense.

To the Fast3D contributors: First, sorry to ping you on a project you didn't directly commit to. We are using a fork of Fast3D developed to allow for binary redistribution. I thought we forked from a Fast3D that has the newest Fast3D license. As mentioned earlier, I recently noticed we had the old license that doesn't allow us to allow binary distribution ports. Ports made on libultraship are meant to have assets loaded externally and not compiled in, so there should be no real concern to binary distribution of ports made with libultraship. I've already discussed this with @Emill, the original author of Fast3D, and he said the switch to MIT license for this fork is fine.

The newest Fast3D license:
https://github.com/Emill/n64-fast3d-engine/blob/master/LICENSE.txt

The current license on the LUS Fast3D fork:
https://github.com/Kenix3/libultraship/blob/main/src/graphic/Fast3D/LICENSE.txt

The new proposed license:

MIT License

Copyright (c) 2020 Emill, MaikelChan

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

Affirming to the new license will mean that any contributions you've made to the Fast3D project, either in this repository (https://github.com/Kenix3/libultraship), the HarbourMasters/Shipwright repository (https://github.com/HarbourMasters/Shipwright), or the original Fast3D repository (https://github.com/Emill/n64-fast3d-engine) to be licensed under the MIT license as proposed above. This also means the original location of the moved Fast3D files. The changes are currently represented in the Fast3D directory in libultraship at https://github.com/Kenix3/libultraship/tree/main/src/graphic/Fast3D.

Please post in this issue whether or not you affirm that the license change is OK and that you have the ability to submit this code under the MIT license. Please also post if there are any comments or questions that we can address.

Thankyou everyone.

libultraship contributors:
@Kenix3 @NEstelami @KiritoDv @dcvz @louist103 @Emill @briaguya-ai @Rozelette @GaryOderNichts @garrettjoecox @jbodner09 @GreatArgorath @Random06457 @AloXado320 @th-2021 @JoshDuMan @andrewwvc @MaikelChan

Fast3D contributors:
@Emill @MaikelChan @DarkRTA @AloXado320 @aglab2

Fullscreen doesn't save monitor

If I exited SoH while it was in fullscreen and at my second monitor, the next start is always in fullscreen at my primary monitor. after that toggling back to windowed makes the window jump back to my secondary monitor.

TLDR: Monitor saves fine for windowed mode. It doesn't in fullscreen.

SoH build with PR HarbourMasters/Shipwright#2881

linux gyro support

not sure what it'll take to get this working consistently, but it seems to be a problem across multiple different controllers

gSPBranchList is broken and crashes any DL that uses it

Per a conversation had about it, "gSPBranchList should be the equivalent of gSPDisplayList(), followed by gSPEndDisplayList()". Libultraship's implementation of it can be found here, and it is not a correct implementation:

Instead of:

} else {
    cmd = (Gfx*)seg_addr(cmd->words.w1);
}

It should probably be something like:

} else {
  cmd++;
  uint64_t hash = ((uint64_t)cmd->words.w0 << 32) + cmd->words.w1;
  cmd = (Gfx*)ResourceGetDataByCrc(hash);
  --cmd; // increase after break
}

Thanks for the suggested fix, @Rozelette .

Window size is not correctly persisted for Mac (probably retina screens)

As of #288 , window size is now persisted through application restarts. On Mac, potentially only on retina screens, this value is not persisted correctly.

When the application is closed, the value stored is double what it should be.

Repro:
Open <game>.json
Set Window.Height and Window.Width to 500
Open application and observe it booted with the correct width/height.
Observe value in json file has not been touched.
Close application
Observe value in json has been doubled
Re-open application and observe the width/height is now double what it should be

decouple physical devices from LUS controllers

the current state of things

the logic currently lives in

  • ControlDeck
  • Controller
    • DummyController
    • KeyboardController
    • SDLController

so the process for getting controller data into a game is currently

void osContGetReadData(OSContPad* pad) {
memset(pad, 0, sizeof(OSContPad) * __osMaxControllers);
LUS::Context::GetInstance()->GetControlDeck()->WriteToPad(pad);
}

this part makes a lot of sense, we need to have something in LUS that gets player input data intoOSContPad

it then gets a little messier

void ControlDeck::WriteToPad(OSContPad* pad) {
mPads = pad;
for (size_t i = 0; i < mPortList.size(); i++) {
const std::shared_ptr<Controller> backend = mDevices[mPortList[i]];
// If the controller backend is "Auto" we need to get the real device
// we search for the real device to read input from it
if (backend->GetGuid() == "Auto") {
for (const auto& device : mDevices) {
if (IsBlockingGameInput(device->GetGuid())) {
device->ReadToPad(nullptr, i);
continue;
}
device->ReadToPad(&pad[i], i);
}
continue;
}
if (IsBlockingGameInput(backend->GetGuid())) {
backend->ReadToPad(nullptr, i);
continue;
}
backend->ReadToPad(&pad[i], i);
}
}

in this method we've already hit some messy logic. trying to handle "Auto" this way feels like a workaround. that being said, the basic flow makes a lot of sense

void ControlDeck::WriteToPad(OSContPad* pad) {
    mPads = pad;

    for (size_t i = 0; i < mPortList.size(); i++) {
        const std::shared_ptr<Controller> controller = mDevices[mPortList[i]];

        controller->ReadToPad(&pad[i], i);
    }
}

this brings us into

void Controller::ReadToPad(OSContPad* pad, int32_t portIndex) {
ReadDevice(portIndex);

and this is where we start to see a pattern that i think shows the most room for improvement. we're constantly passing around portIndex

all of the controllers need this to know which OSContPad to write do during ReadDevice, so it makes sense that this is happening, but it also leads to ReadDevice methods with a ton of logic in them. The one in SDLController is nearly 200 lines long

void SDLController::ReadDevice(int32_t portIndex) {
auto profile = GetProfile(portIndex);
SDL_GameControllerUpdate();
// If the controller is disconnected, close it.
if (mController != nullptr && !SDL_GameControllerGetAttached(mController)) {
Close();
}
// Attempt to load the controller if it's not loaded
if (mController == nullptr) {
// If we failed to load the controller, don't process it.
if (!Open()) {
return;
}
}
if (mSupportsGyro && profile->UseGyro) {
float gyroData[3];
SDL_GameControllerGetSensorData(mController, SDL_SENSOR_GYRO, gyroData, 3);
float gyroDriftX = profile->GyroData[DRIFT_X] / 100.0f;
float gyroDriftY = profile->GyroData[DRIFT_Y] / 100.0f;
const float gyroSensitivity = profile->GyroData[GYRO_SENSITIVITY];
if (gyroDriftX == 0) {
gyroDriftX = gyroData[0];
}
if (gyroDriftY == 0) {
gyroDriftY = gyroData[1];
}
profile->GyroData[DRIFT_X] = gyroDriftX * 100.0f;
profile->GyroData[DRIFT_Y] = gyroDriftY * 100.0f;
GetGyroX(portIndex) = gyroData[0] - gyroDriftX;
GetGyroY(portIndex) = gyroData[1] - gyroDriftY;
GetGyroX(portIndex) *= gyroSensitivity;
GetGyroY(portIndex) *= gyroSensitivity;
} else {
GetGyroX(portIndex) = 0;
GetGyroY(portIndex) = 0;
}
GetPressedButtons(portIndex) = 0;
for (int32_t i = SDL_CONTROLLER_BUTTON_A; i < SDL_CONTROLLER_BUTTON_MAX; i++) {
if (profile->Mappings.contains(i)) {
if (SDL_GameControllerGetButton(mController, static_cast<SDL_GameControllerButton>(i))) {
GetPressedButtons(portIndex) |= profile->Mappings[i];
} else {
GetPressedButtons(portIndex) &= ~profile->Mappings[i];
}
}
}
SDL_GameControllerAxis leftStickAxisX = SDL_CONTROLLER_AXIS_INVALID;
SDL_GameControllerAxis leftStickAxisY = SDL_CONTROLLER_AXIS_INVALID;
SDL_GameControllerAxis rightStickAxisX = SDL_CONTROLLER_AXIS_INVALID;
SDL_GameControllerAxis rightStickAxisY = SDL_CONTROLLER_AXIS_INVALID;
for (int32_t i = SDL_CONTROLLER_AXIS_LEFTX; i < SDL_CONTROLLER_AXIS_MAX; i++) {
const auto axis = static_cast<SDL_GameControllerAxis>(i);
const auto posScancode = i | AXIS_SCANCODE_BIT;
const auto negScancode = -posScancode;
const auto axisMinimumPress = profile->AxisMinimumPress[i];
const auto axisDeadzone = profile->AxisDeadzones[i];
const auto posButton = profile->Mappings[posScancode];
const auto negButton = profile->Mappings[negScancode];
const auto axisValue = SDL_GameControllerGetAxis(mController, axis);
#ifdef TARGET_WEB
// Firefox has a bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1606562
// It sets down y to 32768.0f / 32767.0f, which is greater than the allowed 1.0f,
// which SDL then converts to a int16_t by multiplying by 32767.0f, which overflows into -32768.
// Maximum up will hence never become -32768 with the current version of SDL2,
// so this workaround should be safe in compliant browsers.
if (AxisValue == -32768) {
AxisValue = 32767;
}
#endif
if (!(posButton == BTN_STICKLEFT || posButton == BTN_STICKRIGHT || posButton == BTN_STICKUP ||
posButton == BTN_STICKDOWN || negButton == BTN_STICKLEFT || negButton == BTN_STICKRIGHT ||
negButton == BTN_STICKUP || negButton == BTN_STICKDOWN || posButton == BTN_VSTICKLEFT ||
posButton == BTN_VSTICKRIGHT || posButton == BTN_VSTICKUP || posButton == BTN_VSTICKDOWN ||
negButton == BTN_VSTICKLEFT || negButton == BTN_VSTICKRIGHT || negButton == BTN_VSTICKUP ||
negButton == BTN_VSTICKDOWN)) {
// The axis is being treated as a "button"
auto axisComparableValue = axisValue;
auto axisMinValue = axisMinimumPress;
if (profile->UseStickDeadzoneForButtons) {
axisComparableValue = NormaliseStickValue(axisValue);
axisMinValue = axisDeadzone;
}
if (axisComparableValue > axisMinValue) {
GetPressedButtons(portIndex) |= posButton;
GetPressedButtons(portIndex) &= ~negButton;
} else if (axisComparableValue < -axisMinValue) {
GetPressedButtons(portIndex) &= ~posButton;
GetPressedButtons(portIndex) |= negButton;
} else {
GetPressedButtons(portIndex) &= ~posButton;
GetPressedButtons(portIndex) &= ~negButton;
}
} else {
// The axis is being treated as a "stick"
// Left stick
if (posButton == BTN_STICKLEFT || posButton == BTN_STICKRIGHT) {
if (leftStickAxisX != SDL_CONTROLLER_AXIS_INVALID && leftStickAxisX != axis) {
SPDLOG_TRACE("Invalid PosStickX configured. Neg was {} and Pos is {}", leftStickAxisX, axis);
}
leftStickAxisX = axis;
}
if (posButton == BTN_STICKUP || posButton == BTN_STICKDOWN) {
if (leftStickAxisY != SDL_CONTROLLER_AXIS_INVALID && leftStickAxisY != axis) {
SPDLOG_TRACE("Invalid PosStickY configured. Neg was {} and Pos is {}", leftStickAxisY, axis);
}
leftStickAxisY = axis;
}
if (negButton == BTN_STICKLEFT || negButton == BTN_STICKRIGHT) {
if (leftStickAxisX != SDL_CONTROLLER_AXIS_INVALID && leftStickAxisX != axis) {
SPDLOG_TRACE("Invalid NegStickX configured. Pos was {} and Neg is {}", leftStickAxisX, axis);
}
leftStickAxisX = axis;
}
if (negButton == BTN_STICKUP || negButton == BTN_STICKDOWN) {
if (leftStickAxisY != SDL_CONTROLLER_AXIS_INVALID && leftStickAxisY != axis) {
SPDLOG_TRACE("Invalid NegStickY configured. Pos was {} and Neg is {}", leftStickAxisY, axis);
}
leftStickAxisY = axis;
}
// Right Stick
if (posButton == BTN_VSTICKLEFT || posButton == BTN_VSTICKRIGHT) {
if (rightStickAxisX != SDL_CONTROLLER_AXIS_INVALID && rightStickAxisX != axis) {
SPDLOG_TRACE("Invalid PosStickX configured. Neg was {} and Pos is {}", rightStickAxisX, axis);
}
rightStickAxisX = axis;
}
if (posButton == BTN_VSTICKUP || posButton == BTN_VSTICKDOWN) {
if (rightStickAxisY != SDL_CONTROLLER_AXIS_INVALID && rightStickAxisY != axis) {
SPDLOG_TRACE("Invalid PosStickY configured. Neg was {} and Pos is {}", rightStickAxisY, axis);
}
rightStickAxisY = axis;
}
if (negButton == BTN_VSTICKLEFT || negButton == BTN_VSTICKRIGHT) {
if (rightStickAxisX != SDL_CONTROLLER_AXIS_INVALID && rightStickAxisX != axis) {
SPDLOG_TRACE("Invalid NegStickX configured. Pos was {} and Neg is {}", rightStickAxisX, axis);
}
rightStickAxisX = axis;
}
if (negButton == BTN_VSTICKUP || negButton == BTN_VSTICKDOWN) {
if (rightStickAxisY != SDL_CONTROLLER_AXIS_INVALID && rightStickAxisY != axis) {
SPDLOG_TRACE("Invalid NegStickY configured. Pos was {} and Neg is {}", rightStickAxisY, axis);
}
rightStickAxisY = axis;
}
}
}
if (leftStickAxisX != SDL_CONTROLLER_AXIS_INVALID && leftStickAxisY != SDL_CONTROLLER_AXIS_INVALID) {
NormalizeStickAxis(leftStickAxisX, leftStickAxisY, portIndex);
}
if (rightStickAxisX != SDL_CONTROLLER_AXIS_INVALID && rightStickAxisY != SDL_CONTROLLER_AXIS_INVALID) {
NormalizeStickAxis(rightStickAxisX, rightStickAxisY, portIndex);
}
}

so what can we do instead?

i propose we restructure where the inheritance lives. so our /controller/ directory could instead look like

  • ControlDeck
  • Controller
  • Mapping (or ButtonMapping but that seems odd if we use it for axes, or Binding)
    • DummyMapping
    • KeyboardMapping
    • SDLMapping

in this proposed architecture nothing would inherit from controller, and controller would have a bunch of mappings as members. instead of calling ReadDevice in ReadToPad, we would ask each mapping for the data we need

what does this get us?

  • more logic would live directly in Controller, simplifying implementation of new input backends.
  • we'd be able to map inputs from multiple devices to one OSContPad

Relocate OOT Factories

All of the OOT specific asset code files and factories should be moved to an LUS module.

I'm thinking that the ResourceLoader stays, but keeps all of the resource types in a map. It exposes a method to register a type. ZAPDTR (or some new module for LUS) will have all of the factories and data classes like PlayerAnimation.

This should also accompany a cleanup of the Resource.h header and it's helper classes. Anything OOT/ZAPD specific should go to ZAPDTR/SOH.

Further ResourceLoader should be a shared_ptr on the resorucemgr, and make everything a class member rather than static function.

Also need to update ResourceType enum.

Bug: Main game window does not persist size & position

From what I can tell all windows created within the port will persist their window size and position, with the exception of the main game window.

This has been a common pain point for people who do not play fullscreen.

CrashHandler fixes.

  • Remove any OOT specific code from CrashHandler.cpp
  • Needs a bridge file for exporting to API.

controller rework v2

wii u related

  • figure out wonkyness with wiimote+nunchuk mappings (it seems nunchuck buttons aren't getting set but the wiimote equivalent are - this is happening in KPadStatus - hold vs nunchuck.hold)

imgui related

  • pressing the menubar toggle button on a controller toggles it twice
    • imgui logic for reading from controllers feels kind of wonky in general, i tried a few things here and nothing felt consistent, i think a true solution to this issue will come with remappable hotkeys outside of imgui (i'm thinking another tab like ports that has hotkey config, then we can use the controldeck and controller and read from the devices with a ___ToHotkeyMapping (this would get us remappable hotkeys)
  • game pausing for disconnect/remap screens
    • once #370 is implemented hook into it
  • disconnected controllers as vector to show which ports are disconnected when multiple disconnected
  • add colored font awesome icon for each controller with a mapping in a port tab
    • imgui tabs just have a label, trying to get multiple colors in a tab label is far from easy in imgui at the moment ocornut/imgui#902
  • persist controller button names when controller is disconnected
  • (super nitpicky) get it so the controller config menu remembers the ordering of mappings when closing and opening the game
  • wrap mappings to next line instead of overflowing to the right, put analog stick preview to the right
  • advanced devices tab functionality
    • show buttons pressed
    • button to force rumble
    • button to force LED
    • sticks
    • gyro
  • have buttons (n64 buttons at the beginnings of lines) light up when an associated mapped button is pressed

not sure if it's a problem

  • handle disconnected controller mappings more elegantly, right now they just fill up the config (this might become an issue with manual clearing, in which case it'll move up to v1)

code cleanup

  • move some of the shared logic out of ControllerStick/ControllerButton/ControllerGyro/ControllerRumble/ControllerLED (maybe just wait and do this as part of attachments)

additional functionality

  • attachments
    • i see the reasoning here, but i don't see a clear path forward for this given the current limitations in how we handle "controller output." i plan to build things in a modular way that should make moving to an attachment system straightforward, but i think it makes sense to make those architectural decisions in a PR separate from this one
  • "chord" style mapping - make it possible to require multiple physical buttons be pressed to activate a virtual button/axis
  • #351
    (see nitpick appendix)

new controller types

  • TAS
    • flag on controller that short circuits ReadToPad and reads from tas instead
    • flag on controller that writes to tas file
    • need to byteswap KiritoDv@bd01dd7
    • ui needs to make it clear that restarting is needed (maybe force now?)

refactor away from giant f3d switch/case ifdef stuff

  • A minimalist approach would be to copy gfx_pc run_dl function, remove the ifdefs, and have a different version of this function per supported GBI.
  • This is basically refactoring Fast3D to not rely on GBI.
  • Fast3D needs to be told what GBI version we are rendering with.
  • Fast3D will need handler functions for each GBI opcode, for each different GBI supported.
  • Design is very inspired by gliden64.
  • It would be nice if Fast3D were a class.
  • ideally support choosing GBI at runtime instead of compile time

switch (opcode) {

#ifdef F3DEX_GBI_2
gfx_sp_matrix(C0(0, 8) ^ G_MTX_PUSH, (const int32_t*)seg_addr(mtxAddr));
#else
gfx_sp_matrix(C0(16, 8), (const int32_t*)seg_addr(cmd->words.w1));
#endif

Feature: CVar support for nested JSON

The interface will remain unchanged where the user will still identify the cvar by a string eg gCosmetics.KokiriTunic.RainbowMode, but the underlying JSON this will be stored as a nested structure

custom `OSContPad`?

the current LUS implementation of OSContPad includes things beyond what exists on the n64 (multiple analog sticks, gyro), but is still very opinionated as to what can exist on the pad.

i think in order to satisfy the two port dev user stories from #342 it could be helpful to add some flexibility here.

To satisfy

As a developer of a port using LUS, I should be able to get up and running without building my own controller mapping/configuration menu.

it could be helpful to provide controller functionality that utilizes an OSContPad that matches the authentic data structure. Only including n64 buttons/one analog stick. The existing LUS controller functionality could then be provided via OSContPadExtended, which would provide the default "modern controller" version of OSContPad that exists in LUS today (n64 controller + a few extra things)

To satisfy

As a developer of a port using LUS, I should be able to provide a tailored controller mapping/configuration experience for players.

we would want to provide the ability for any given port could provide their own OSContPad structure that can deviate as far from the authentic n64 controller OSContPad as the port would like. This would allow for a port to create an OSContPad structure based on in-game actions, for example, instead of having

#define BTN_CRIGHT 0x00001
#define BTN_CLEFT 0x00002
#define BTN_CDOWN 0x00004
#define BTN_CUP 0x00008

a port could have

#define ACTION_OCARINA_A4 0x00001 
#define ACTION_OCARINA_B4 0x00002 
#define ACTION_OCARINA_F4 0x00004 
#define ACTION_OCARINA_D4 0x00008 
#define ACTION_ITEM_RIGHT 0x00010 
#define ACTION_ITEM_LEFT 0x00020 
#define ACTION_ITEM_DOWN 0x00040  

this would be very port specific, as each port would know which actions they would want to be able to map (as opposed to relying on original n64 controller mapping to game actions), so LUS wouldn't need to provide any examples or UI for this, just the framework to do so

Turn ImGui implementation into a class.

  • Turn ImGui into a C++ class.
  • Class should follow LUS naming conventions.
  • Include a reference to the imgui class on what we currently call the Window class.
  • Create a bridge for the Imgui functions to be in the LUS API.

Detect GFX renderer init failure and attempt fallback to secondary renderer

Some Windows users have reported a crash on launch that happens in the LUS::Window init -> gfx_init
Investigation revealed that it was an issue with DX11 on their machines. Since DX11 is the default renderer for Windows when there is no existing configuration, this leaves the user stuck without the ability to run. Guiding the user to modify their configuration to use OpenGL instead resolved the crash.

In the case of Windows, it would be nice to be able to detect a gfx_init failure and try to fallback to the OpenGL renderer so that users are not required to manually modify configuration files.

Here is the crash log when using DX11 on the problematic machines:

Registers: 
RAX: 0x0000000000000000
RCX: 0x0000000200000001
RDX: 0x0000000100000004
RBX: 0x00007FF640D67CE8
RSP: 0x0000008190B0DFF0
RBP: 0x0000008190B0E260
RSI: 0x0000008190B0E160
RDI: 0x0000000019930520
R9:  0x0000000100000060
R10: 0x0000006000000001
R11: 0x0000000000000000
R12: 0x0000000000000000
R13: 0x0000000000000003
R14: 0x0000000000000000
R15: 0x00007FF640AD6D50
RIP: 0x00007FFFEBB2CB69
EFLAGS: 0x00000202
At RaiseExceptionAddr: 0x00007FFFEBB2CB00
In: C:\Windows\System32\KERNELBASE.dll
_CxxThrowException in D:\a\_work\1\s\src\vctools\crt\vcruntime\src\eh\throw.cppLine: 75At ?ThrowIfFailed@@YAXJ@ZAddr: 0x00007FF640791810
In: C:\Users\TOSHIBA\Desktop\zelda ocarina of time\soh.exe
At ?do_get@?$num_get@DV?$istreambuf_iterator@DU?$char_traits@D@std@@@std@@@std@@MEBA?AV?$istreambuf_iterator@DU?$char_traits@D@std@@@2@V32@0AEAVios_base@2@AEAHAEA_N@ZAddr: 0x00007FF6407889B0
In: C:\Users\TOSHIBA\Desktop\zelda ocarina of time\soh.exe
At ?gfx_init@@YAXPEAUGfxWindowManagerAPI@@PEAUGfxRenderingAPI@@PEBD_NII@ZAddr: 0x00007FF640755CA0
In: C:\Users\TOSHIBA\Desktop\zelda ocarina of time\soh.exe
At ?Init@Window@LUS@@QEAAXXZAddr: 0x00007FF64073FB40
In: C:\Users\TOSHIBA\Desktop\zelda ocarina of time\soh.exe
At ?InitWindow@Context@LUS@@QEAAXXZAddr: 0x00007FF64073BD50
In: C:\Users\TOSHIBA\Desktop\zelda ocarina of time\soh.exe
At ?Init@Context@LUS@@QEAAXAEBV?$vector@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@2@@std@@AEBV?$unordered_set@IU?$hash@I@std@@U?$equal_to@I@2@V?$allocator@I@2@@4@I@ZAddr: 0x00007FF64073A190
In: C:\Users\TOSHIBA\Desktop\zelda ocarina of time\soh.exe
At ?CreateInstance@Context@LUS@@SA?AV?$shared_ptr@VContext@LUS@@@std@@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@4@0AEBV?$vector@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@2@@4@AEBV?$unordered_set@IU?$hash@I@std@@U?$equal_to@I@2@V?$allocator@I@2@@4@I@ZAddr: 0x00007FF640739C00
In: C:\Users\TOSHIBA\Desktop\zelda ocarina of time\soh.exe
OTRGlobals::OTRGlobals in D:\a\Shipwright\Shipwright\soh\soh\OTRGlobals.cppLine: 244InitOTR in D:\a\Shipwright\Shipwright\soh\soh\OTRGlobals.cppLine: 745SDL_main in D:\a\Shipwright\Shipwright\soh\src\code\main.cLine: 65main_getcmdline in D:\a\Shipwright\Shipwright\build-windows\vcpkg\buildtrees\sdl2\src\ase-2.26.5-fdc15bb8fb.clean\src\main\windows\SDL_windows_main.cLine: 82__scrt_common_main_seh in D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inlLine: 288At BaseThreadInitThunkAddr: 0x00007FFFECFE75F0
In: C:\Windows\System32\KERNEL32.DLL
At RtlUserThreadStartAddr: 0x00007FFFEE122680
In: C:\Windows\SYSTEM32\ntdll.dll

`ConsoleVariable::SetColor24` doesn't properly save

when we set using SetColor24 the Color24 variable is set

void ConsoleVariable::SetColor24(const char* name, Color_RGB8 value) {
auto& variable = mVariables[name];
if (!variable) {
variable = std::make_shared<CVar>();
}
variable->Type = ConsoleVariableType::Color24;
variable->Color24 = value;
}

but then when we go to save the Color variable is read

} else if (variable.second->Type == ConsoleVariableType::Color ||
variable.second->Type == ConsoleVariableType::Color24) {
auto keyStr = key.c_str();
Color_RGBA8 clr = variable.second->Color;
conf->SetUInt(StringHelper::Sprintf("%s.R", keyStr), clr.r);
conf->SetUInt(StringHelper::Sprintf("%s.G", keyStr), clr.g);
conf->SetUInt(StringHelper::Sprintf("%s.B", keyStr), clr.b);
if (variable.second->Type == ConsoleVariableType::Color) {
conf->SetUInt(StringHelper::Sprintf("%s.A", keyStr), clr.a);
conf->SetString(StringHelper::Sprintf("%s.Type", keyStr), "RGBA");
} else {
conf->SetString(StringHelper::Sprintf("%s.Type", keyStr), "RGB");
}
}

leading to {0, 0, 0} always being saved for Color24

Linux: On screen keyboard no longer works

With LUS 1.0.0 it seems input from the on screen keyboard in SteamOS no longer works. Specifically any key that would type a character. Arrow keys and backspace appear to be unaffected.

Have not tested on other Linux OS or other platforms yet.

Create an example project for LUS

We can find some simple open source N64 code/game to port using LUS to use as an example project on how to implement LUS.
Create some instructions as well on how LUS was integrated into the example project.
Ideally this example project would build for both N64 and PC.

Turn Fast3D into a class.

  • Turn Fast3D into a C++ class.
  • Class should follow LUS naming conventions.
  • Include a reference to the renderer class on what we currently call the Window class.
  • Create a bridge for the Fast3D functions to be in the LUS API.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.