update some deps + android build fix and downloader

This commit is contained in:
Alula 2021-12-02 09:21:06 +01:00
parent eaaa11d4f6
commit 75e05c5ca5
No known key found for this signature in database
GPG Key ID: 3E00485503A1D8BA
11 changed files with 375 additions and 124 deletions

View File

@ -59,7 +59,7 @@ cpal = { git = "https://github.com/doukutsu-rs/cpal.git", rev = "4218ff23242834d
directories = "3"
funty = "=1.1.0" # https://github.com/bitvecto-rs/bitvec/issues/105
glutin = { git = "https://github.com/doukutsu-rs/glutin.git", rev = "8dd457b9adb7dbac7ade337246b6356c784272d9", optional = true, default_features = false, features = ["x11"] }
imgui = "0.7.0"
imgui = "0.8.0"
image = { version = "0.23", default-features = false, features = ["png", "bmp"] }
itertools = "0.10"
lazy_static = "1.4.0"

View File

@ -62,6 +62,11 @@ android {
dependencies {
implementation 'com.android.support:support-annotations:28.0.0'
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support:design:28.0.0'
implementation 'com.android.support.constraint:constraint-layout:2.0.1'
implementation 'android.arch.navigation:navigation-fragment:1.0.0'
implementation 'android.arch.navigation:navigation-ui:1.0.0'
}
println("cargo target: ${project.buildDir.getAbsolutePath()}/rust-target")

View File

@ -1,40 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="io.github.doukutsu_rs">
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="io.github.doukutsu_rs">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:extractNativeLibs="true"
<application android:allowBackup="true" android:extractNativeLibs="true" android:icon="@mipmap/ic_launcher"
android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true"
android:theme="@style/Theme.Doukutsurs">
<provider
android:name=".DoukutsuDocumentsProvider"
android:authorities="${documentsAuthority}"
android:exported="true"
android:grantUriPermissions="true"
android:permission="android.permission.MANAGE_DOCUMENTS">
<intent-filter>
<action
android:name="android.content.action.DOCUMENTS_PROVIDER"/>
</intent-filter>
</provider>
<activity
android:name="io.github.doukutsu_rs.MainActivity"
android:label="doukutsu-rs"
android:screenOrientation="sensorLandscape"
android:launchMode="standard"
android:configChanges="orientation|keyboardHidden|screenSize">
<meta-data android:name="android.app.lib_name" android:value="drsandroid" />
<activity android:name=".DownloadActivity" android:label="Download" android:screenOrientation="sensorLandscape"
android:theme="@style/Theme.Doukutsurs.NoActionBar"></activity>
<activity android:name=".MainActivity" android:configChanges="orientation|keyboardHidden|screenSize"
android:label="doukutsu-rs" android:launchMode="standard" android:screenOrientation="sensorLandscape">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data android:name="android.app.lib_name" android:value="drsandroid" />
</activity>
<provider android:name=".DoukutsuDocumentsProvider" android:authorities="${documentsAuthority}"
android:exported="true" android:grantUriPermissions="true"
android:permission="android.permission.MANAGE_DOCUMENTS">
<intent-filter>
<action android:name="android.content.action.DOCUMENTS_PROVIDER" />
</intent-filter>
</provider>
</application>
</manifest>

View File

@ -0,0 +1,139 @@
package io.github.doukutsu_rs;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.ProgressBar;
import android.widget.TextView;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Locale;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
public class DownloadActivity extends AppCompatActivity {
private TextView txtProgress;
private ProgressBar progressBar;
private DownloadThread downloadThread;
private String basePath;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_download);
txtProgress = findViewById(R.id.txtProgress);
progressBar = findViewById(R.id.progressBar);
basePath = getFilesDir().getAbsolutePath() + "/data/";
downloadThread = new DownloadThread();
downloadThread.start();
}
@Override
protected void onDestroy() {
super.onDestroy();
downloadThread.interrupt();
}
private class DownloadThread extends Thread {
private static final String DOWNLOAD_URL = "https://github.com/doukutsu-rs/game-data/archive/refs/heads/master.zip";
@Override
public void run() {
HttpURLConnection connection = null;
try {
URL url = new URL(DOWNLOAD_URL);
connection = (HttpURLConnection) url.openConnection();
connection.connect();
if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
throw new IllegalStateException("Bad HTTP response code: " + connection.getResponseCode());
}
int fileLength = connection.getContentLength();
if (fileLength == 0) {
progressBar.setIndeterminate(true);
}
byte[] zipFile;
{
InputStream input = new BufferedInputStream(connection.getInputStream());
ByteArrayOutputStream output = new ByteArrayOutputStream();
int downloadedLast = 0;
int downloaded = 0;
byte[] buffer = new byte[4096];
int count;
long last = System.currentTimeMillis();
while ((count = input.read(buffer)) != -1) {
downloaded += count;
output.write(buffer, 0, count);
long now = System.currentTimeMillis();
if (last + 1000 >= now) {
int speed = (int) ((downloaded - downloadedLast) / 1024.0);
String text = (fileLength > 0)
? String.format(Locale.ENGLISH, "Downloading... %d%% (%d/%d KiB, %d KiB/s)", downloaded * 100 / fileLength, downloaded / 1024, fileLength / 1024, speed)
: String.format(Locale.ENGLISH, "Downloading... --%% (%d KiB, %d KiB/s)", downloaded / 1024, speed);
txtProgress.setText(text);
downloadedLast = downloaded;
last = now;
}
}
output.flush();
zipFile = output.toByteArray();
output.close();
}
new File(basePath).mkdirs();
try (ZipInputStream in = new ZipInputStream(new ByteArrayInputStream(zipFile))) {
ZipEntry entry;
byte[] buffer = new byte[4096];
while ((entry = in.getNextEntry()) != null) {
String entryName = entry.getName();
// strip prefix
if (entryName.startsWith("game-data-master/")) {
entryName = entryName.substring("game-data-master/".length());
}
txtProgress.setText("Unpacking: " + entryName);
if (entry.isDirectory()) {
new File(basePath + entryName).mkdirs();
} else {
try (FileOutputStream fos = new FileOutputStream(basePath + entryName)) {
int count;
while ((count = in.read(buffer)) != -1) {
fos.write(buffer, 0, count);
}
}
}
in.closeEntry();
}
}
txtProgress.setText("Done!");
Intent intent = new Intent(DownloadActivity.this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_TASK_ON_HOME);
startActivity(intent);
DownloadActivity.this.finish();
} catch (Exception e) {
if (txtProgress != null) txtProgress.setText(e.getMessage());
e.printStackTrace();
} finally {
if (connection != null) connection.disconnect();
}
}
}
}

View File

@ -1,6 +1,8 @@
package io.github.doukutsu_rs;
import android.app.AlertDialog;
import android.app.NativeActivity;
import android.content.Intent;
import android.content.res.Configuration;
import android.hardware.SensorManager;
import android.os.Build;
@ -8,6 +10,8 @@ import android.os.Bundle;
import android.view.OrientationEventListener;
import android.view.WindowInsets;
import java.io.File;
import static android.os.Build.VERSION.SDK_INT;
public class MainActivity extends NativeActivity {
@ -16,6 +20,18 @@ public class MainActivity extends NativeActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
File f = new File(getFilesDir().getAbsolutePath() + "/data/");
String[] list = f.list();
if (!f.exists() || (list != null && list.length == 0)) {
messageBox("Missing data files", "No data files found, would you like to download them?", () -> {
Intent intent = new Intent(this, DownloadActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_TASK_ON_HOME);
startActivity(intent);
this.finish();
});
}
super.onCreate(savedInstanceState);
listener = new OrientationEventListener(this, SensorManager.SENSOR_DELAY_UI) {
@ -70,6 +86,8 @@ public class MainActivity extends NativeActivity {
this.displayInsets[1] = Math.max(this.displayInsets[1], insets.getStableInsetTop());
this.displayInsets[2] = Math.max(this.displayInsets[2], insets.getStableInsetRight());
this.displayInsets[3] = Math.max(this.displayInsets[3], insets.getStableInsetBottom());
} else {
return;
}
if (SDK_INT >= Build.VERSION_CODES.P) {
@ -84,4 +102,19 @@ public class MainActivity extends NativeActivity {
}
}
private void messageBox(String title, String message, Runnable callback) {
this.runOnUiThread(() -> {
AlertDialog.Builder alert = new AlertDialog.Builder(this);
alert.setTitle(title);
alert.setMessage(message);
alert.setPositiveButton(android.R.string.yes, (dialog, whichButton) -> {
callback.run();
});
alert.setNegativeButton(android.R.string.no, (dialog, whichButton) -> {
// hide
});
alert.show();
});
}
}

View File

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".DownloadActivity">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="32dp"
android:layout_marginStart="32dp"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:id="@+id/txtTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Downloading game data"
android:textAlignment="center"
android:textAppearance="@style/TextAppearance.AppCompat.Display1" />
<TextView
android:id="@+id/txtProgress"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="..."
android:textAlignment="center"
android:textAppearance="@style/TextAppearance.AppCompat.Small" />
<ProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</android.support.constraint.ConstraintLayout>

View File

@ -0,0 +1,3 @@
<resources>
<dimen name="fab_margin">16dp</dimen>
</resources>

View File

@ -3,4 +3,13 @@
<style name="Theme.Doukutsurs" parent="@android:style/Theme.DeviceDefault.NoActionBar.Fullscreen">
</style>
</resources>
<style name="Theme.Doukutsurs.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
</style>
<style name="Theme.Doukutsurs.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />
<style name="Theme.Doukutsurs.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />
</resources>

View File

@ -8,7 +8,7 @@ buildscript {
}
}
dependencies {
classpath "com.android.tools.build:gradle:4.0.2"
classpath "com.android.tools.build:gradle:4.2.0"
classpath "gradle.plugin.com.github.willir.rust:plugin:0.3.4"
// NOTE: Do not place your application dependencies here; they belong

View File

@ -5,9 +5,8 @@ use std::ffi::c_void;
use std::rc::Rc;
use std::time::Duration;
use imgui::{ConfigFlags, DrawCmd, DrawData, ImString, Key, MouseCursor, TextureId};
use imgui::internal::RawWrapper;
use sdl2::{EventPump, keyboard, pixels, Sdl, VideoSubsystem};
use imgui::{ConfigFlags, DrawCmd, DrawData, Key, MouseCursor, TextureId};
use sdl2::event::{Event, WindowEvent};
use sdl2::keyboard::Scancode;
use sdl2::mouse::{Cursor, SystemCursor};
@ -15,6 +14,7 @@ use sdl2::pixels::PixelFormatEnum;
use sdl2::render::{Texture, TextureCreator, WindowCanvas};
use sdl2::video::GLProfile;
use sdl2::video::WindowContext;
use sdl2::{keyboard, pixels, EventPump, Sdl, VideoSubsystem};
use crate::common::{Color, Rect};
use crate::framework::backend::{
@ -309,7 +309,7 @@ impl SDL2Renderer {
let mut imgui = init_imgui()?;
let mut imgui_textures = HashMap::new();
imgui.set_renderer_name(ImString::new("SDL2Renderer"));
imgui.set_renderer_name("SDL2Renderer".to_owned());
{
let refs = refs.clone();
let mut fonts = imgui.fonts();
@ -1006,23 +1006,23 @@ pub struct ImguiSdl2 {
struct Sdl2ClipboardBackend(sdl2::clipboard::ClipboardUtil);
impl imgui::ClipboardBackend for Sdl2ClipboardBackend {
fn get(&mut self) -> Option<imgui::ImString> {
fn get(&mut self) -> Option<String> {
if !self.0.has_clipboard_text() {
return None;
}
self.0.clipboard_text().ok().map(imgui::ImString::new)
self.0.clipboard_text().ok()
}
fn set(&mut self, value: &imgui::ImStr) {
let _ = self.0.set_clipboard_text(value.to_str());
fn set(&mut self, value: &str) {
let _ = self.0.set_clipboard_text(value);
}
}
impl ImguiSdl2 {
pub fn new(imgui: &mut imgui::Context, window: &sdl2::video::Window) -> Self {
let clipboard_util = window.subsystem().clipboard();
imgui.set_clipboard_backend(Box::new(Sdl2ClipboardBackend(clipboard_util)));
imgui.set_clipboard_backend(Sdl2ClipboardBackend(clipboard_util));
imgui.io_mut().key_map[Key::Tab as usize] = Scancode::Tab as u32;
imgui.io_mut().key_map[Key::LeftArrow as usize] = Scancode::Left as u32;

View File

@ -1,11 +1,11 @@
use imgui::{CollapsingHeader, Condition, im_str, ImStr, ImString, Slider, Window};
use imgui::{ CollapsingHeader, Condition, ImStr, ImString, Slider, Window};
use itertools::Itertools;
use crate::framework::context::Context;
use crate::framework::error::GameResult;
use crate::scene::game_scene::GameScene;
use crate::shared_game_state::SharedGameState;
use crate::scripting::tsc::text_script::TextScriptExecutionState;
use crate::shared_game_state::SharedGameState;
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
#[repr(u8)]
@ -49,7 +49,13 @@ impl LiveDebugger {
}
}
pub fn run_ingame(&mut self, game_scene: &mut GameScene, state: &mut SharedGameState, ctx: &mut Context, ui: &mut imgui::Ui) -> GameResult {
pub fn run_ingame(
&mut self,
game_scene: &mut GameScene,
state: &mut SharedGameState,
ctx: &mut Context,
ui: &mut imgui::Ui,
) -> GameResult {
if self.last_stage_id != game_scene.stage_id {
self.last_stage_id = game_scene.stage_id;
self.events.clear();
@ -60,7 +66,7 @@ impl LiveDebugger {
return Ok(());
}
Window::new(im_str!("Debugger"))
Window::new("Debugger")
.resizable(false)
.collapsed(true, Condition::FirstUseEver)
.position([5.0, 5.0], Condition::FirstUseEver)
@ -91,14 +97,11 @@ impl LiveDebugger {
game_scene.player1.booster_fuel
));
ui.text(format!("Game speed ({:.1} TPS):", state.current_tps()));
let mut speed = state.settings.speed;
Slider::new(im_str!(""))
.range(0.1..=3.0)
.build(ui, &mut speed);
ui.same_line(0.0);
if ui.button(im_str!("Reset"), [0.0, 0.0]) {
Slider::new("", 0.1, 3.0).build(ui, &mut speed);
ui.same_line();
if ui.button("Reset") {
speed = 1.0
}
@ -107,47 +110,47 @@ impl LiveDebugger {
state.set_speed(speed);
}
if ui.button(im_str!("Maps"), [0.0, 0.0]) {
if ui.button("Maps") {
self.map_selector_visible = !self.map_selector_visible;
}
ui.same_line(0.0);
if ui.button(im_str!("TSC Scripts"), [0.0, 0.0]) {
ui.same_line();
if ui.button("TSC Scripts") {
self.events_visible = !self.events_visible;
}
ui.same_line(0.0);
if ui.button(im_str!("Flags"), [0.0, 0.0]) {
ui.same_line();
if ui.button("Flags") {
self.flags_visible = !self.flags_visible;
}
#[cfg(feature = "scripting-lua")]
{
ui.same_line(0.0);
if ui.button(im_str!("Reload Lua Scripts"), [0.0, 0.0]) {
if let Err(err) = state.lua.reload_scripts(ctx) {
log::error!("Error reloading scripts: {:?}", err);
self.error = Some(ImString::new(err.to_string()));
}
{
ui.same_line();
if ui.button("Reload Lua Scripts") {
if let Err(err) = state.lua.reload_scripts(ctx) {
log::error!("Error reloading scripts: {:?}", err);
self.error = Some(ImString::new(err.to_string()));
}
}
}
if game_scene.player2.cond.alive() {
if ui.button(im_str!("Drop Player 2"), [0.0, 0.0]) {
if ui.button("Drop Player 2") {
game_scene.drop_player2();
}
} else if ui.button(im_str!("Add Player 2"), [0.0, 0.0]) {
} else if ui.button("Add Player 2") {
game_scene.add_player2();
}
ui.same_line(0.0);
ui.same_line();
if ui.button(im_str!("NPC Inspector"), [0.0, 0.0]) {
if ui.button("NPC Inspector") {
self.npc_inspector_visible = !self.npc_inspector_visible;
}
});
if self.map_selector_visible {
Window::new(im_str!("Map selector"))
Window::new("Map selector")
.resizable(false)
.position([80.0, 80.0], Condition::Appearing)
.size([240.0, 280.0], Condition::Appearing)
@ -157,17 +160,18 @@ impl LiveDebugger {
self.stages.push(ImString::new(s.name.to_owned()));
}
self.selected_stage = match state.stages.iter().find_position(|s| s.name == game_scene.stage.data.name) {
Some((pos, _)) => { pos as i32 }
_ => { -1 }
};
self.selected_stage =
match state.stages.iter().find_position(|s| s.name == game_scene.stage.data.name) {
Some((pos, _)) => pos as i32,
_ => -1,
};
}
let stages: Vec<&ImStr> = self.stages.iter().map(|e| e.as_ref()).collect();
ui.push_item_width(-1.0);
ui.list_box(im_str!(""), &mut self.selected_stage, &stages, 10);
ui.list_box("", &mut self.selected_stage, &stages, 10);
if ui.button(im_str!("Load"), [0.0, 0.0]) {
if ui.button("Load") {
match GameScene::new(state, ctx, self.selected_stage as usize) {
Ok(mut scene) => {
let tile_size = scene.stage.map.tile_size.as_int() * 0x200;
@ -204,7 +208,7 @@ impl LiveDebugger {
}
if self.events_visible {
Window::new(im_str!("TSC Scripts"))
Window::new("TSC Scripts")
.resizable(false)
.position([80.0, 80.0], Condition::Appearing)
.size([300.0, 320.0], Condition::Appearing)
@ -236,13 +240,19 @@ impl LiveDebugger {
}
let events: Vec<&ImStr> = self.events.iter().map(|e| e.as_ref()).collect();
ui.text_wrapped(&ImString::new(format!("TextScript execution state: {:?}", state.textscript_vm.state)));
ui.text_wrapped(&ImString::new(format!("CreditScript execution state: {:?}", state.creditscript_vm.state)));
ui.text_wrapped(&ImString::new(format!(
"TextScript execution state: {:?}",
state.textscript_vm.state
)));
ui.text_wrapped(&ImString::new(format!(
"CreditScript execution state: {:?}",
state.creditscript_vm.state
)));
ui.push_item_width(-1.0);
ui.list_box(im_str!(""), &mut self.selected_event, &events, 10);
ui.list_box("", &mut self.selected_event, &events, 10);
if ui.button(im_str!("Execute"), [0.0, 0.0]) {
if ui.button("Execute") {
assert_eq!(self.event_ids.len(), self.events.len());
if let Some((_, event_num)) = self.event_ids.get(self.selected_event as usize) {
@ -252,8 +262,8 @@ impl LiveDebugger {
}
}
ui.same_line(0.0);
if ui.button(im_str!("Decompile"), [0.0, 0.0]) {
ui.same_line();
if ui.button("Decompile") {
if let Some((stype, event_num)) = self.event_ids.get(self.selected_event as usize) {
let id = ((*stype as u32) << 16) | (*event_num as u32);
if !self.text_windows.iter().any(|(e, _, _)| *e == id) {
@ -270,11 +280,14 @@ impl LiveDebugger {
self.text_windows.push((
id,
ImString::new(format!("Decompiled event: #{:04}", *event_num)),
ImString::new(code)
ImString::new(code),
));
}
Err(e) => {
self.error = Some(ImString::new(format!("Error decompiling TextScript #{:04}: {}", *event_num, e)));
self.error = Some(ImString::new(format!(
"Error decompiling TextScript #{:04}: {}",
*event_num, e
)));
}
}
}
@ -284,55 +297,57 @@ impl LiveDebugger {
}
if self.flags_visible {
Window::new(im_str!("Flags"))
Window::new("Flags")
.position([80.0, 80.0], Condition::FirstUseEver)
.size([280.0, 300.0], Condition::FirstUseEver)
.build(ui, || {
if CollapsingHeader::new(im_str!("Control flags")).default_open(false).build(&ui) {
ui.checkbox_flags(im_str!("Tick world"), &mut state.control_flags.0, 1);
ui.checkbox_flags(im_str!("Control enabled"), &mut state.control_flags.0, 2);
ui.checkbox_flags(im_str!("Interactions disabled"), &mut state.control_flags.0, 4);
ui.checkbox_flags(im_str!("Credits running"), &mut state.control_flags.0, 8);
if CollapsingHeader::new("Control flags").default_open(false).build(&ui) {
ui.checkbox_flags("Tick world", &mut state.control_flags.0, 1);
ui.checkbox_flags("Control enabled", &mut state.control_flags.0, 2);
ui.checkbox_flags("Interactions disabled", &mut state.control_flags.0, 4);
ui.checkbox_flags("Credits running", &mut state.control_flags.0, 8);
ui.separator();
ui.checkbox_flags(im_str!("[Internal] Windy level"), &mut state.control_flags.0, 15);
ui.checkbox_flags("[Internal] Windy level", &mut state.control_flags.0, 15);
}
if CollapsingHeader::new(im_str!("Player condition flags")).default_open(false).build(&ui) {
if CollapsingHeader::new("Player condition flags").default_open(false).build(&ui) {
cond_flags(&ui, &mut game_scene.player1.cond);
}
if CollapsingHeader::new(im_str!("Player equipment")).default_open(false).build(&ui) {
ui.checkbox_flags(im_str!("Booster 0.8"), &mut game_scene.player1.equip.0, 1);
ui.checkbox_flags(im_str!("Map System"), &mut game_scene.player1.equip.0, 2);
ui.checkbox_flags(im_str!("Arms Barrier"), &mut game_scene.player1.equip.0, 4);
ui.checkbox_flags(im_str!("Turbocharge"), &mut game_scene.player1.equip.0, 8);
ui.checkbox_flags(im_str!("Air Tank"), &mut game_scene.player1.equip.0, 16);
ui.checkbox_flags(im_str!("Booster 2.0"), &mut game_scene.player1.equip.0, 32);
ui.checkbox_flags(im_str!("Mimiga Mask"), &mut game_scene.player1.equip.0, 64);
ui.checkbox_flags(im_str!("Whimsical Star"), &mut game_scene.player1.equip.0, 128);
ui.checkbox_flags(im_str!("Nikumaru Counter"), &mut game_scene.player1.equip.0, 256);
if CollapsingHeader::new("Player equipment").default_open(false).build(&ui) {
ui.checkbox_flags("Booster 0.8", &mut game_scene.player1.equip.0, 1);
ui.checkbox_flags("Map System", &mut game_scene.player1.equip.0, 2);
ui.checkbox_flags("Arms Barrier", &mut game_scene.player1.equip.0, 4);
ui.checkbox_flags("Turbocharge", &mut game_scene.player1.equip.0, 8);
ui.checkbox_flags("Air Tank", &mut game_scene.player1.equip.0, 16);
ui.checkbox_flags("Booster 2.0", &mut game_scene.player1.equip.0, 32);
ui.checkbox_flags("Mimiga Mask", &mut game_scene.player1.equip.0, 64);
ui.checkbox_flags("Whimsical Star", &mut game_scene.player1.equip.0, 128);
ui.checkbox_flags("Nikumaru Counter", &mut game_scene.player1.equip.0, 256);
}
});
}
if self.npc_inspector_visible {
Window::new(im_str!("NPC Inspector"))
Window::new("NPC Inspector")
.position([80.0, 80.0], Condition::FirstUseEver)
.size([280.0, 300.0], Condition::FirstUseEver)
.scrollable(true)
.always_vertical_scrollbar(true)
.build(ui, || {
for npc in game_scene.npc_list.iter_alive() {
if CollapsingHeader::new(&ImString::from(format!("id={} type={}", npc.id, npc.npc_type))).default_open(false).build(&ui) {
if CollapsingHeader::new(&ImString::from(format!("id={} type={}", npc.id, npc.npc_type)))
.default_open(false)
.build(&ui)
{
let mut position = [npc.x as f32 / 512.0, npc.y as f32 / 512.0];
ui.input_float2(im_str!("Position:"), &mut position)
.build();
ui.input_float2("Position:", &mut position).build();
npc.x = (position[0] * 512.0) as i32;
npc.y = (position[1] * 512.0) as i32;
let content = &ImString::from(
format!("\
let content = &ImString::from(format!(
"\
Velocity: ({:.1},{:.1})\n\
Vel2/State2: ({:.1},{:.1} / {} {})\n\
Animation: frame={}, counter={}\n\
@ -340,13 +355,24 @@ impl LiveDebugger {
Health: {}, Experience drop: {}\n\
Event ID: {}, Flag ID: {}\n\
Parent: {}, Shock: {}, Size: {}",
npc.vel_x as f32 / 512.0, npc.vel_y as f32 / 512.0,
npc.vel_x2 as f32 / 512.0, npc.vel_y2 as f32 / 512.0, npc.vel_x2, npc.vel_y2,
npc.anim_num, npc.anim_counter,
npc.action_num, npc.action_counter, npc.action_counter2,
npc.life, npc.exp,
npc.event_num, npc.flag_num,
npc.parent_id, npc.shock, npc.size
npc.vel_x as f32 / 512.0,
npc.vel_y as f32 / 512.0,
npc.vel_x2 as f32 / 512.0,
npc.vel_y2 as f32 / 512.0,
npc.vel_x2,
npc.vel_y2,
npc.anim_num,
npc.anim_counter,
npc.action_num,
npc.action_counter,
npc.action_counter2,
npc.life,
npc.exp,
npc.event_num,
npc.flag_num,
npc.parent_id,
npc.shock,
npc.size
));
ui.text_wrapped(content);
@ -378,16 +404,19 @@ impl LiveDebugger {
}
if self.error.is_some() {
Window::new(im_str!("Error!"))
Window::new("Error!")
.resizable(false)
.collapsible(false)
.position([((state.screen_size.0 - 300.0) / 2.0).floor(), ((state.screen_size.1 - 100.0) / 2.0).floor()], Condition::Appearing)
.position(
[((state.screen_size.0 - 300.0) / 2.0).floor(), ((state.screen_size.1 - 100.0) / 2.0).floor()],
Condition::Appearing,
)
.size([300.0, 100.0], Condition::Appearing)
.build(ui, || {
ui.push_item_width(-1.0);
ui.text_wrapped(self.error.as_ref().unwrap());
if ui.button(im_str!("OK"), [0.0, 0.0]) {
if ui.button("OK") {
self.error = None;
}
});
@ -398,12 +427,12 @@ impl LiveDebugger {
}
fn cond_flags(ui: &imgui::Ui, cond: &mut crate::common::Condition) {
ui.checkbox_flags(im_str!("Interacted"), &mut cond.0, 1);
ui.checkbox_flags(im_str!("Hidden"), &mut cond.0, 2);
ui.checkbox_flags(im_str!("Fallen"), &mut cond.0, 4);
ui.checkbox_flags(im_str!("Built-in NPC destroy handler"), &mut cond.0, 8);
ui.checkbox_flags(im_str!("Damage first boss NPC"), &mut cond.0, 16);
ui.checkbox_flags(im_str!("Increased acceleration"), &mut cond.0, 32);
ui.checkbox_flags(im_str!("Unknown (0x40)"), &mut cond.0, 64);
ui.checkbox_flags(im_str!("Alive"), &mut cond.0, 128);
ui.checkbox_flags("Interacted", &mut cond.0, 1);
ui.checkbox_flags("Hidden", &mut cond.0, 2);
ui.checkbox_flags("Fallen", &mut cond.0, 4);
ui.checkbox_flags("Built-in NPC destroy handler", &mut cond.0, 8);
ui.checkbox_flags("Damage first boss NPC", &mut cond.0, 16);
ui.checkbox_flags("Increased acceleration", &mut cond.0, 32);
ui.checkbox_flags("Unknown (0x40)", &mut cond.0, 64);
ui.checkbox_flags("Alive", &mut cond.0, 128);
}