mirror of
https://gitea.tendokyu.moe/ppc/amnet.git
synced 2026-10-07 22:28:13 +03:00
Compare commits
6
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bff0416f00 | ||
|
|
701a92dea5 | ||
|
|
3f17f9b432 | ||
|
|
6146f1c409 | ||
|
|
9b2c62c035 | ||
|
|
e77f401e0c |
@@ -74,7 +74,7 @@ export default function CardManager({navigation}) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<FlatList contentInsetAdjustmentBehavior="always"
|
<FlatList contentInsetAdjustmentBehavior="always"
|
||||||
style={{padding: 16}}
|
style={{padding: 16, paddingTop: 24}}
|
||||||
data={cards}
|
data={cards}
|
||||||
keyExtractor={i => i._id.toString()}
|
keyExtractor={i => i._id.toString()}
|
||||||
contentContainerStyle={{paddingBottom: 120}}
|
contentContainerStyle={{paddingBottom: 120}}
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
import {BSON} from "realm";
|
import {BSON} from "realm";
|
||||||
import {ActivityIndicator, Button, Text, useTheme} from "react-native-paper";
|
import {ActivityIndicator, Button, Text, useTheme} from "react-native-paper";
|
||||||
import React, {useCallback, useEffect, useLayoutEffect, useMemo, useState} from "react";
|
import React, {useCallback, useEffect, useLayoutEffect, useMemo, useState} from "react";
|
||||||
import {Alert, Platform, RefreshControl, ScrollView, Share, View} from "react-native";
|
import {Alert, Platform, RefreshControl, ScrollView, Share, StyleSheet, View} from "react-native";
|
||||||
import {useSafeAreaInsets} from "react-native-safe-area-context";
|
|
||||||
import {
|
import {
|
||||||
CircleCheck,
|
CircleCheck,
|
||||||
CircleDot,
|
CircleDot,
|
||||||
@@ -42,8 +41,7 @@ const {useRealm, useQuery, useObject} = RealmContext;
|
|||||||
|
|
||||||
export default function ServerCardIn({route, navigation}) {
|
export default function ServerCardIn({route, navigation}) {
|
||||||
const realm = useRealm();
|
const realm = useRealm();
|
||||||
const theme = useTheme();
|
const theme = useTheme()
|
||||||
const insets = useSafeAreaInsets();
|
|
||||||
|
|
||||||
const {serverId} = route.params;
|
const {serverId} = route.params;
|
||||||
const server = useObject(AMServer, ObjectId.createFromHexString(serverId));
|
const server = useObject(AMServer, ObjectId.createFromHexString(serverId));
|
||||||
@@ -218,8 +216,7 @@ export default function ServerCardIn({route, navigation}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ScrollView contentInsetAdjustmentBehavior="always"
|
<ScrollView contentInsetAdjustmentBehavior="automatic" refreshControl={<RefreshControl refreshing={serverRefreshing} onRefresh={performRefresh}/>}>
|
||||||
refreshControl={<RefreshControl refreshing={serverRefreshing} onRefresh={performRefresh}/>}>
|
|
||||||
<View style={styles.container}>
|
<View style={styles.container}>
|
||||||
<StatusAlert server={server} connectionEstablished={serverConnectionSuccess}/>
|
<StatusAlert server={server} connectionEstablished={serverConnectionSuccess}/>
|
||||||
<View style={styles.section}>
|
<View style={styles.section}>
|
||||||
@@ -347,21 +344,21 @@ const menuActions: MenuAction[] = [
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
const styles = {
|
const styles = StyleSheet.create({
|
||||||
section: {
|
section: {
|
||||||
gap: 10
|
gap: 10
|
||||||
},
|
},
|
||||||
sectionTitle: {
|
sectionTitle: {
|
||||||
fontWeight: "bold" as const
|
fontWeight: "bold"
|
||||||
},
|
},
|
||||||
emptyPlaceholderView: {
|
emptyPlaceholderView: {
|
||||||
marginVertical: 30,
|
marginVertical: 30,
|
||||||
gap: 15
|
gap: 15
|
||||||
},
|
},
|
||||||
container: {
|
container: {
|
||||||
paddingTop: Platform.select({android: 18, default: 0}),
|
paddingTop: Platform.select({android: 120, default: 0}),
|
||||||
paddingHorizontal: 16,
|
paddingHorizontal: 16,
|
||||||
paddingBottom: 80,
|
paddingBottom: 80,
|
||||||
gap: 20
|
gap: 20
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ export default function ServerManager({navigation}) {
|
|||||||
<FlatList contentInsetAdjustmentBehavior="always"
|
<FlatList contentInsetAdjustmentBehavior="always"
|
||||||
data={servers}
|
data={servers}
|
||||||
keyExtractor={i => i._id.toString()}
|
keyExtractor={i => i._id.toString()}
|
||||||
style={{padding: 16}}
|
style={{padding: 16, paddingTop: 24}}
|
||||||
contentContainerStyle={{paddingBottom: 80}}
|
contentContainerStyle={{paddingBottom: 80}}
|
||||||
renderItem={i => <ServerCard navigation={navigation} server={i.item}/>}
|
renderItem={i => <ServerCard navigation={navigation} server={i.item}/>}
|
||||||
ItemSeparatorComponent={() => <View style={{height: 15}}/>}
|
ItemSeparatorComponent={() => <View style={{height: 15}}/>}
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ export default function ServerManagerStack({navigation}) {
|
|||||||
headerRight: () => Platform.OS === 'android' ? null : <TouchableOpacity onPress={() => navigation.navigate('add-server')}><Plus color={theme.colors.primary}/></TouchableOpacity>
|
headerRight: () => Platform.OS === 'android' ? null : <TouchableOpacity onPress={() => navigation.navigate('add-server')}><Plus color={theme.colors.primary}/></TouchableOpacity>
|
||||||
}}/>
|
}}/>
|
||||||
|
|
||||||
<Stack.Screen name="server" options={{title: "Server", headerTransparent: Platform.select({default: false, ios: true})}} component={ServerCardIn}/>
|
<Stack.Screen name="server" options={{title: "Server", headerTransparent: true}} component={ServerCardIn}/>
|
||||||
</Stack.Group>
|
</Stack.Group>
|
||||||
</Stack.Navigator>
|
</Stack.Navigator>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -84,7 +84,4 @@ function MethodCard(props: {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Platform.select({
|
export default CardAddModal;
|
||||||
default: ManualCardEntry,
|
|
||||||
ios: CardAddModal
|
|
||||||
});
|
|
||||||
@@ -96,10 +96,13 @@ impl Config {
|
|||||||
.map(|v| v > 0)
|
.map(|v| v > 0)
|
||||||
.unwrap_or(defaults::AIME_KEYBOARD_ENABLED);
|
.unwrap_or(defaults::AIME_KEYBOARD_ENABLED);
|
||||||
|
|
||||||
let aime_txt_path = aime_section
|
let aime_txt_path_raw = aime_section
|
||||||
.and_then(|s| s.get("aimePath"))
|
.and_then(|s| s.get("aimePath"))
|
||||||
.unwrap_or(defaults::AIME_FILE)
|
.unwrap_or(defaults::AIME_FILE);
|
||||||
.into();
|
|
||||||
|
// Normalize backslashes to forward slashes to avoid escape issues
|
||||||
|
let aime_txt_path_str = aime_txt_path_raw.replace("\\", "/");
|
||||||
|
let aime_txt_path = PathBuf::from(aime_txt_path_str);
|
||||||
|
|
||||||
let server_listen_address = io_section.get("listenAddress")
|
let server_listen_address = io_section.get("listenAddress")
|
||||||
.unwrap_or(defaults::SERVER_ADDRESS)
|
.unwrap_or(defaults::SERVER_ADDRESS)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
use axum::http::{StatusCode, header};
|
use axum::http::{Method, StatusCode, header};
|
||||||
use axum::response::{IntoResponse, Response};
|
use axum::response::{IntoResponse, Response};
|
||||||
use axum::routing::{get, post};
|
use axum::routing::{get, post};
|
||||||
use axum::{Json, Router};
|
use axum::{Json, Router};
|
||||||
@@ -16,7 +16,7 @@ use crate::webapi::API_VERSION;
|
|||||||
pub fn build_server() -> Router {
|
pub fn build_server() -> Router {
|
||||||
let services = ServiceBuilder::new()
|
let services = ServiceBuilder::new()
|
||||||
.layer(TraceLayer::new_for_http())
|
.layer(TraceLayer::new_for_http())
|
||||||
.layer(CorsLayer::new().allow_origin(Any).allow_methods(Any));
|
.layer(CorsLayer::new().allow_origin(Any).allow_headers(Any).allow_methods([Method::GET, Method::POST]).max_age(Duration::from_secs(600)));
|
||||||
|
|
||||||
Router::<()>::new()
|
Router::<()>::new()
|
||||||
.route("/amnet/info", get(server_state_handler))
|
.route("/amnet/info", get(server_state_handler))
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<div align="center">
|
<div align="center">
|
||||||
|
|
||||||
# AMNet
|
# AMNet
|
||||||
[Firebase](https://appdistribution.firebase.dev/i/6acc3151357deaa8) • [Website](http://card.ppc.moe) • [Server DLLs](https://gitea.tendokyu.moe/ppc/amnet/releases)
|
[Latest .ipa](https://amnet-dist.ppc.moe/amnet-1.3.9.ipa) • [Firebase](https://appdistribution.firebase.dev/i/6acc3151357deaa8) • [Website](http://card.ppc.moe) • [Server DLLs](https://gitea.tendokyu.moe/ppc/amnet/releases)
|
||||||
|
|
||||||
An Amusement IC Card Switcher for segatools-based games.
|
An Amusement IC Card Switcher for segatools-based games.
|
||||||
|
|
||||||
@@ -13,7 +13,6 @@ This was originally intended for use with maimai and CHUNITHM, but should be com
|
|||||||
|
|
||||||
> [!WARNING]
|
> [!WARNING]
|
||||||
> TestFlight is no longer available and must be sideloaded using AltStore or similar tooling for the forseeable future.
|
> TestFlight is no longer available and must be sideloaded using AltStore or similar tooling for the forseeable future.
|
||||||
> See issue #1 for more details.
|
|
||||||
|
|
||||||
## Setup
|
## Setup
|
||||||
1. Download the latest `amnet.dll` from the releases page
|
1. Download the latest `amnet.dll` from the releases page
|
||||||
@@ -40,6 +39,18 @@ This was originally intended for use with maimai and CHUNITHM, but should be com
|
|||||||
4. Launch the game, and check the amdaemon console for server startup messages
|
4. Launch the game, and check the amdaemon console for server startup messages
|
||||||
5. Access the using one of the interfaces (see below), add a new server `http://<your-ip-address>:6070`, import your existing card (or create a new one) and start playing!
|
5. Access the using one of the interfaces (see below), add a new server `http://<your-ip-address>:6070`, import your existing card (or create a new one) and start playing!
|
||||||
|
|
||||||
|
### Physical Cards
|
||||||
|
AMNet 1.3 adds support for scanning physical cards on iOS devices. If you own a physical Aime/Banapass/NESiCA/e-Amusement card, you can scan it using the app and use it in-game.
|
||||||
|
By changing the `useAimeDBForPhysicalCards` in segatools.ini, you can choose how the card is read on a per-game basis:
|
||||||
|
|
||||||
|
- `0` will send the 20-digit access code on the back of the card to the game and load the save data directly (default option).
|
||||||
|
- `1` - Send the card's IDm to the game and use AiMeDB to retrieve the 20-digit code assigned to the card.
|
||||||
|
|
||||||
|
Mode `1` makes the app function in the same way to a real card reader and should be used if you want the same access code to show when scanning the card on a cab.
|
||||||
|
You should also use this option if you're connecting to a hosted server (AquaNet/rinnet/etc).
|
||||||
|
|
||||||
|
Additionally, if `useAimeDBForPhysicalCards` is set to `1` and the game is failing to read the card, make sure an up-to-date version of segatools is being used.
|
||||||
|
|
||||||
## Interfaces
|
## Interfaces
|
||||||
AMNet can be used on most platforms, see below for options available for each platform:
|
AMNet can be used on most platforms, see below for options available for each platform:
|
||||||
|
|
||||||
@@ -52,8 +63,8 @@ AMNet can be used on most platforms, see below for options available for each pl
|
|||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>iOS</td>
|
<td>iOS</td>
|
||||||
<td><a href="https://amnet-dist.ppc.moe/amnet-1.3.2.ipa" target="_blank">.ipa download</a></td>
|
<td><a href="https://amnet-dist.ppc.moe/amnet-1.3.9.ipa" target="_blank">.ipa</a></td>
|
||||||
<td>*TestFlight is no longer available, sideload using AltStore or similar tooling</td>
|
<td>*TestFlight has been shut down and won't be back for the forseeable future, sideload using AltStore or similar tooling</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td rowspan="2">Android</td>
|
<td rowspan="2">Android</td>
|
||||||
|
|||||||
Reference in New Issue
Block a user