Compare commits
No commits in common. "a41f44080d21e688bef582ae67916f0d87d57521" and "623d5c307cf5244a7bd649991fa4c8a425611152" have entirely different histories.
a41f44080d
...
623d5c307c
37
README.md
37
README.md
@ -1,37 +0,0 @@
|
|||||||
#Murderator
|
|
||||||
|
|
||||||
Ce programme permet d'organiser, de gérer et planifier des soirées «Murder» ou «huis-clos». L'objectif est d'aider le ou les opérateurs à garder une trace de quels objets sont dans quelles salles, qui a utilisé quel pouvoir quand.
|
|
||||||
|
|
||||||
##### Compilation
|
|
||||||
> Pour complier, une simple commande `gradle jar` crée un fichier jar fonctionnel dans le dossier `build/libs/`
|
|
||||||
|
|
||||||
### Utilisation
|
|
||||||
|
|
||||||
Pour chaque session ou partie, un ordinateur doit utiliser un terminal maître, qui sera créé un chargant un fichier décrivant l'état initial de la Murder. Un exemple de tel fichier est donné dans le dossier `src/test/resources`.
|
|
||||||
|
|
||||||
##### Objets
|
|
||||||
Un simple système de drag&drop permet de déplacer facilement les objets, même à travers les onglets, avec sélection au survol. Les menus au clic droit permettent de créer/renommer/supprimer les objets.
|
|
||||||
##### Actions
|
|
||||||
Un seul bouton à actionner et les actions sont «déclenchées». Elles peuvent aussi être réinitialisées avec le menu clic droit.
|
|
||||||
##### Enceinte et microphones
|
|
||||||
D'autres ordinateurs peuvent être utilisés comme serveur enceinte ou microphones. Afin de les connecter, il faut d'abord sélectionner l'interface audio à utiliser, puis indiquer l'adresse IP du terminal maître. L'appareil devrait alors apparaître sur le terminal maître. Ensuite, les enceintes peuvent se connecter à n'importe quel micro.
|
|
||||||
|
|
||||||
### Principe
|
|
||||||
|
|
||||||
L'application est écrite selon un système MVC (Model/Vue/Contrôlleur). Le modèle est un ensemble de classes Java décrivant la Partie, présentes dans le paquet `com.bernard.murder.model`
|
|
||||||
|
|
||||||
La vue est définie de manière modulaire, à travers des «Minels». Les minels, présents dans le paquet `com.bernard.murder.view.minel`, implémentent une fonction `genContentPane()` qui sera appelée une fois et qui renvoie un Panel qui sera présent dans la fenêtre.
|
|
||||||
|
|
||||||
Les minels et les onglets présents sont définis dans la classe `MinelsCreator`.
|
|
||||||
|
|
||||||
Dans le cas où plusieurs terminal sont présents, il n'y a qu'un seul terminal maître qui a l'assurance de l'intégrité des données.
|
|
||||||
|
|
||||||
### Fonctionalités
|
|
||||||
|
|
||||||
##### Partie
|
|
||||||
* Stoquage et déplacement des objets dans les salles et les inventaires
|
|
||||||
* Actions des joueurs
|
|
||||||
|
|
||||||
##### Application
|
|
||||||
* Sauvegardes automatiques de la partie et des minels
|
|
||||||
* Allumage et Extinction propre des serveurs
|
|
||||||
20
build.gradle
20
build.gradle
@ -12,22 +12,10 @@ apply plugin: 'eclipse'
|
|||||||
repositories {
|
repositories {
|
||||||
// Use jcenter for resolving dependencies.
|
// Use jcenter for resolving dependencies.
|
||||||
// You can declare any Maven/Ivy/file repository here.
|
// You can declare any Maven/Ivy/file repository here.
|
||||||
|
jcenter()
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
task apiJar(type: Jar) {
|
|
||||||
archiveFileName = "MurderatorAPI.jar"
|
|
||||||
group 'build'
|
|
||||||
description "Fait un jar avec juste l'api"
|
|
||||||
from(sourceSets.main.output) {
|
|
||||||
include "com/bernard/murder/model/**"
|
|
||||||
include "com/bernard/murder/audio/Serveur*.class"
|
|
||||||
include "com/bernard/murder/audio/Codes*.class"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
jar {
|
jar {
|
||||||
manifest {
|
manifest {
|
||||||
attributes(
|
attributes(
|
||||||
@ -41,9 +29,7 @@ jar {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
|
||||||
implementation 'com.amihaiemil.web:eo-yaml:5.2.1'
|
implementation 'com.amihaiemil.web:eo-yaml:5.1.3'
|
||||||
implementation 'com.formdev:flatlaf:1.3'
|
implementation 'com.formdev:flatlaf:0.37'
|
||||||
|
|
||||||
implementation files('../../bernard/BernardLibs.git/build/libs/BernardLibs.jar')
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,11 +0,0 @@
|
|||||||
class: com.bernard.murder.Parametres
|
|
||||||
minielTitleFont:
|
|
||||||
name: Dialog
|
|
||||||
style: 1
|
|
||||||
size: 12
|
|
||||||
textPanMinielBackgroundColor: 0xffffe085
|
|
||||||
textPanMinielTextColor: 0xff274290
|
|
||||||
minielMinSize: 200x300
|
|
||||||
minielParLigne: 2
|
|
||||||
lignesDeMinielAvantScroll: 2
|
|
||||||
lookAndFeel: "flatlaf-light"
|
|
||||||
20
src/main/java/com/bernard/murder/BytesUtils.java
Executable file
20
src/main/java/com/bernard/murder/BytesUtils.java
Executable file
@ -0,0 +1,20 @@
|
|||||||
|
package com.bernard.murder;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
public class BytesUtils {
|
||||||
|
|
||||||
|
public static String readString(ByteBuffer buffer) {
|
||||||
|
int stringLength = buffer.getInt();
|
||||||
|
byte[] stringData = new byte[stringLength];
|
||||||
|
buffer.get(stringData);
|
||||||
|
return new String(stringData);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void writeString(ByteBuffer buffer, String s) {
|
||||||
|
byte[] data = s.getBytes();
|
||||||
|
buffer.putInt(data.length);
|
||||||
|
buffer.put(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,42 +0,0 @@
|
|||||||
package com.bernard.murder;
|
|
||||||
|
|
||||||
import java.awt.Color;
|
|
||||||
import java.awt.Dimension;
|
|
||||||
import java.awt.Font;
|
|
||||||
import java.awt.font.TextAttribute;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import javax.swing.UIManager;
|
|
||||||
|
|
||||||
import com.bernard.configurator.annotations.ConfigClass;
|
|
||||||
|
|
||||||
@ConfigClass(requireOption = false)
|
|
||||||
public class Parametres {
|
|
||||||
|
|
||||||
public static Parametres instance;
|
|
||||||
|
|
||||||
public Font minielTitleFont = UIManager.getFont("Label.font");
|
|
||||||
|
|
||||||
public Color textPanMinielBackgroundColor = new Color(0xFFE085);
|
|
||||||
public Color textPanMinielTextColor = new Color(0x274290);
|
|
||||||
|
|
||||||
|
|
||||||
public Dimension minielMinSize = new Dimension(200, 300);
|
|
||||||
public int minielParLigne = 2;
|
|
||||||
public int lignesDeMinielAvantScroll = 2;
|
|
||||||
|
|
||||||
public String lookAndFeel = "flatlaf-darcula";
|
|
||||||
|
|
||||||
public String encryptionAlg = "RSA";
|
|
||||||
public int encryptionKeySize = 2048;
|
|
||||||
|
|
||||||
public Parametres() {
|
|
||||||
Map<TextAttribute, Object> ftAttrs = new HashMap<>(minielTitleFont.getAttributes());
|
|
||||||
ftAttrs.put(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON);
|
|
||||||
minielTitleFont = minielTitleFont.deriveFont(Font.BOLD).deriveFont(ftAttrs);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
147
src/main/java/com/bernard/murder/ParseUtils.java
Normal file
147
src/main/java/com/bernard/murder/ParseUtils.java
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
package com.bernard.murder;
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.LocalTime;
|
||||||
|
import java.time.ZoneId;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.Spliterator;
|
||||||
|
import java.util.Spliterators;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
import java.util.stream.StreamSupport;
|
||||||
|
|
||||||
|
import com.amihaiemil.eoyaml.Yaml;
|
||||||
|
import com.amihaiemil.eoyaml.YamlMapping;
|
||||||
|
import com.amihaiemil.eoyaml.YamlMappingBuilder;
|
||||||
|
import com.amihaiemil.eoyaml.YamlNode;
|
||||||
|
import com.amihaiemil.eoyaml.YamlSequence;
|
||||||
|
import com.amihaiemil.eoyaml.YamlSequenceBuilder;
|
||||||
|
|
||||||
|
public class ParseUtils {
|
||||||
|
|
||||||
|
|
||||||
|
static Pattern timeLengthPattern = Pattern.compile("^(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s?)?$");
|
||||||
|
|
||||||
|
public static long parseTimeLength(String tl) {
|
||||||
|
Matcher mtch = timeLengthPattern.matcher(tl);
|
||||||
|
if(!mtch.matches())throw new IllegalArgumentException("La chaine de caractères «"+tl+"» ne décrit pas un intervalle de temps normalisé");
|
||||||
|
int h = mtch.group(2)==null?0:Integer.parseInt(mtch.group(2));
|
||||||
|
int m = mtch.group(4)==null?0:Integer.parseInt(mtch.group(4));
|
||||||
|
int s = mtch.group(6)==null?0:Integer.parseInt(mtch.group(6));
|
||||||
|
return (h*3600+m*60+s)*1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> T watch(T el) {
|
||||||
|
System.out.println(el);
|
||||||
|
return el;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static String dumpTimeLength(long t) {
|
||||||
|
long h=t/1000/3600, m=t/1000/60%60, s=t/1000%60;
|
||||||
|
return (h!=0?h+"h":"" )+ (m!=0?m+"m":"")+(s!=0?s+"s":"");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static String dumpHourDate(long t) {
|
||||||
|
return DateTimeFormatter.ISO_LOCAL_TIME.format(LocalTime.ofInstant(Instant.ofEpochMilli(t-t%1000), ZoneId.systemDefault()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static <T> Set<T> union(Collection<T> c1, Collection<T> c2){
|
||||||
|
Set<T> out = c1.stream().collect(Collectors.toSet());
|
||||||
|
out.addAll(c2);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isSubWord(String word, String subword) {
|
||||||
|
int i=0,j=0;
|
||||||
|
while(true) {
|
||||||
|
if(i==subword.length())return true;
|
||||||
|
if(j==word.length())return false;
|
||||||
|
if(subword.charAt(i)==word.charAt(j))i++;
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean and(boolean[] bb) {
|
||||||
|
for(boolean b : bb)
|
||||||
|
if(!b)return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static Set<String> mappingKeys(YamlMapping mapping) throws IOException{
|
||||||
|
return mapping.keys().stream().map(n ->n.asScalar().value()).collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static Stream<YamlNode> sequenceStream(YamlSequence sequence){
|
||||||
|
return StreamSupport.stream(Spliterators.spliteratorUnknownSize(sequence.iterator(),Spliterator.ORDERED),false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> Function<YamlNode,T> wetherMapping(Function<YamlNode,T> fnot,Function<YamlMapping,T> fyes){
|
||||||
|
return n -> (n instanceof YamlMapping)?fyes.apply((YamlMapping)n):fnot.apply(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Color randColor() {
|
||||||
|
return Color.getHSBColor((float) Math.random(), 1.0f, 1.0f);
|
||||||
|
}
|
||||||
|
public static Color randDarkColor() {
|
||||||
|
return Color.getHSBColor((float) Math.random(), 1.0f, 0.3f);
|
||||||
|
}
|
||||||
|
public static Color randDarkBlueColor() {
|
||||||
|
// 180° to 240°
|
||||||
|
return Color.getHSBColor( (float) (0.5f + 0.2f*Math.random()), 1.0f, 0.3f);
|
||||||
|
}
|
||||||
|
public static Color getContrastColor(Color color) {
|
||||||
|
double y = (299 * color.getRed() + 587 * color.getGreen() + 114 * color.getBlue()) / 1000;
|
||||||
|
return y >= 128 ? Color.black : Color.white;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static final <M> YamlMapping setToMapSS(Set<M> nodes, Function<M,String> key, Function<M,String> value) {
|
||||||
|
YamlMappingBuilder builder = Yaml.createYamlMappingBuilder();
|
||||||
|
for(M n : nodes)
|
||||||
|
builder = builder.add(key.apply(n), value.apply(n));
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
public static final <M> YamlMapping setToMapSY(Set<M> nodes, Function<M,String> key, Function<M,YamlNode> value) {
|
||||||
|
YamlMappingBuilder builder = Yaml.createYamlMappingBuilder();
|
||||||
|
for(M n : nodes)
|
||||||
|
builder = builder.add(key.apply(n), value.apply(n));
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
public static final <M> YamlMapping setToMapYS(Set<M> nodes, Function<M,YamlNode> key, Function<M,String> value) {
|
||||||
|
YamlMappingBuilder builder = Yaml.createYamlMappingBuilder();
|
||||||
|
for(M n : nodes)
|
||||||
|
builder = builder.add(key.apply(n), value.apply(n));
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
public static final <M> YamlMapping setToMapYY(Set<M> nodes, Function<M,YamlNode> key, Function<M,YamlNode> value) {
|
||||||
|
YamlMappingBuilder builder = Yaml.createYamlMappingBuilder();
|
||||||
|
for(M n : nodes)
|
||||||
|
builder = builder.add(key.apply(n), value.apply(n));
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
public static final <M> YamlSequence setToSeqY(Set<YamlNode> nodes) {
|
||||||
|
YamlSequenceBuilder builder = Yaml.createYamlSequenceBuilder();
|
||||||
|
for(YamlNode n : nodes)
|
||||||
|
builder = builder.add(n);
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
public static final <M> YamlSequence setToSeqS(Set<String> nodes) {
|
||||||
|
YamlSequenceBuilder builder = Yaml.createYamlSequenceBuilder();
|
||||||
|
for(String n : nodes)
|
||||||
|
builder = builder.add(n);
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
120
src/main/java/com/bernard/murder/YamlUtils.java
Executable file
120
src/main/java/com/bernard/murder/YamlUtils.java
Executable file
@ -0,0 +1,120 @@
|
|||||||
|
package com.bernard.murder;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
|
import java.util.function.BinaryOperator;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
import java.util.stream.Collector;
|
||||||
|
|
||||||
|
import com.amihaiemil.eoyaml.Node;
|
||||||
|
import com.amihaiemil.eoyaml.Yaml;
|
||||||
|
import com.amihaiemil.eoyaml.YamlMapping;
|
||||||
|
import com.amihaiemil.eoyaml.YamlMappingBuilder;
|
||||||
|
import com.amihaiemil.eoyaml.YamlNode;
|
||||||
|
import com.amihaiemil.eoyaml.YamlSequence;
|
||||||
|
import com.amihaiemil.eoyaml.YamlSequenceBuilder;
|
||||||
|
|
||||||
|
|
||||||
|
public class YamlUtils {
|
||||||
|
|
||||||
|
|
||||||
|
public static final YamlSequence listToSeq(List<YamlNode> nodes) {
|
||||||
|
YamlSequenceBuilder ysb = Yaml.createYamlSequenceBuilder();
|
||||||
|
for(YamlNode n : nodes)
|
||||||
|
ysb = ysb.add(n);
|
||||||
|
return ysb.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final YamlSequence listToSeqString(List<String> nodes) {
|
||||||
|
YamlSequenceBuilder ysb = Yaml.createYamlSequenceBuilder();
|
||||||
|
for(String n : nodes)
|
||||||
|
ysb = ysb.add(n);
|
||||||
|
return ysb.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final YamlMapping mapToMapping(Map<YamlNode,YamlNode> nodes) {
|
||||||
|
YamlMappingBuilder ysb = Yaml.createYamlMappingBuilder();
|
||||||
|
for(Entry<YamlNode, YamlNode> n : nodes.entrySet())
|
||||||
|
ysb = ysb.add(n.getKey(),n.getValue());
|
||||||
|
return ysb.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final YamlSequence getSequence(YamlNode node) {
|
||||||
|
if(node.type()==Node.SEQUENCE)return node.asSequence();
|
||||||
|
if(node.type()==Node.SCALAR && node.asScalar().value().contentEquals("[]"))return Yaml.createYamlSequenceBuilder().build();
|
||||||
|
throw new IllegalArgumentException("Le noeud n'est pas une séquence");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final YamlMapping getMapping(YamlNode node) {
|
||||||
|
if(node.type()==Node.MAPPING)return node.asMapping();
|
||||||
|
if(node.type()==Node.SCALAR && node.asScalar().value().contentEquals("{}"))return Yaml.createYamlMappingBuilder().build();
|
||||||
|
throw new IllegalArgumentException("Le noeud n'est pas une séquence");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final boolean isMapping(YamlNode node) {
|
||||||
|
return (node.type()==Node.MAPPING) || (node.type()==Node.SCALAR && node.asScalar().value().contentEquals("{}"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final boolean isSequence(YamlNode node) {
|
||||||
|
return (node.type()==Node.SEQUENCE) || (node.type()==Node.SCALAR && node.asScalar().value().contentEquals("[]"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (Copied from Collectors class)
|
||||||
|
* Simple implementation class for {@code Collector}.
|
||||||
|
*
|
||||||
|
* @param <T> the type of elements to be collected
|
||||||
|
* @param <R> the type of the result
|
||||||
|
*/
|
||||||
|
static class CollectorImpl<T, A, R> implements Collector<T, A, R> {
|
||||||
|
private final Supplier<A> supplier;
|
||||||
|
private final BiConsumer<A, T> accumulator;
|
||||||
|
private final BinaryOperator<A> combiner;
|
||||||
|
private final Function<A, R> finisher;
|
||||||
|
private final Set<Characteristics> characteristics;
|
||||||
|
|
||||||
|
CollectorImpl(Supplier<A> supplier,
|
||||||
|
BiConsumer<A, T> accumulator,
|
||||||
|
BinaryOperator<A> combiner,
|
||||||
|
Function<A,R> finisher,
|
||||||
|
Set<Characteristics> characteristics) {
|
||||||
|
this.supplier = supplier;
|
||||||
|
this.accumulator = accumulator;
|
||||||
|
this.combiner = combiner;
|
||||||
|
this.finisher = finisher;
|
||||||
|
this.characteristics = characteristics;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BiConsumer<A, T> accumulator() {
|
||||||
|
return accumulator;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Supplier<A> supplier() {
|
||||||
|
return supplier;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BinaryOperator<A> combiner() {
|
||||||
|
return combiner;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Function<A, R> finisher() {
|
||||||
|
return finisher;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<Characteristics> characteristics() {
|
||||||
|
return characteristics;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -6,148 +6,103 @@ import java.net.SocketException;
|
|||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Base64;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.concurrent.ThreadLocalRandom;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.function.Consumer;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import javax.sound.sampled.AudioFormat;
|
import javax.sound.sampled.AudioFormat;
|
||||||
import javax.swing.JOptionPane;
|
|
||||||
|
|
||||||
import com.amihaiemil.eoyaml.Yaml;
|
import com.bernard.murder.BytesUtils;
|
||||||
import com.amihaiemil.eoyaml.YamlMapping;
|
|
||||||
import com.amihaiemil.eoyaml.YamlNode;
|
|
||||||
import com.amihaiemil.eoyaml.YamlSequenceBuilder;
|
|
||||||
import com.bernard.murder.game.GameManager;
|
|
||||||
import com.bernard.murder.game.GameNetworkInterface;
|
|
||||||
import com.bernard.murder.model.Personnage;
|
|
||||||
import com.bernard.util.BytesUtils;
|
|
||||||
import com.bernard.util.ParseUtils;
|
|
||||||
import com.bernard.util.YamlUtils;
|
|
||||||
|
|
||||||
public class AudioServer {
|
public class AudioServer {
|
||||||
|
|
||||||
|
// Format des paquets [commande 1, UUID identifier, byte deviceType, String name]
|
||||||
|
public static final byte DECLARE_NUMBER = 0x02;
|
||||||
|
// Format des paquets [commande 1, UUID identifier, byte deviceType, int id]
|
||||||
|
public static final byte OK_ID = 0x03;
|
||||||
|
// Format des paquets [commande 1]
|
||||||
|
public static final byte ASK_AUDIO_LIST= 0x04;
|
||||||
|
// Format des paquets [commande 1, int Count, {int id, String name}]
|
||||||
|
public static final byte GIVE_AUDIO_LIST = 0x05;
|
||||||
|
// Format des paquets: [commande 1, int listenId, int myId]
|
||||||
|
public static final byte ASK_STREAMING = 0x06;
|
||||||
|
// Format des paquets: [commande 1, int id]
|
||||||
|
public static final byte START_STREAMING = 0x07;
|
||||||
|
// Format des paquets: [commande 1, int listenId, int myId]
|
||||||
|
public static final byte ASK_STOP_STREAMING = 0x09;
|
||||||
|
// Format des paquets: [commande 1, int id]
|
||||||
|
public static final byte STOP_STREAMING = 0x08;
|
||||||
|
// Format des paquets [commande 1, int id, ~ data]
|
||||||
|
public static final byte AUDIO_STREAM = 0x01;
|
||||||
|
|
||||||
|
|
||||||
|
public static final byte SPEAKER_DEVICE = 0x01;
|
||||||
|
public static final byte MIC_DEVICE = 0x02;
|
||||||
|
|
||||||
|
|
||||||
public static AudioFormat formatAudio = new AudioFormat(8000f, 16, 1, true, true);
|
public static AudioFormat formatAudio = new AudioFormat(8000f, 16, 1, true, true);
|
||||||
|
public static int packetMaxSize = 97282;
|
||||||
|
public static int communicationPort = 35295;
|
||||||
|
|
||||||
public Serveur serveur;
|
public Serveur serveur;
|
||||||
|
|
||||||
int micId = 0;
|
int micId = 0;
|
||||||
int speakerId = 0;
|
int speakerId = 0;
|
||||||
|
|
||||||
private GameNetworkInterface gameInterface;
|
|
||||||
|
|
||||||
Map<Integer,String> mics;
|
Map<Integer,String> mics;
|
||||||
Map<Integer,String> speakers;
|
Map<Integer,String> speakers;
|
||||||
Map<Integer,SocketAddress> micsAddr;
|
Map<Integer,SocketAddress> micsAddr;
|
||||||
Map<Integer,SocketAddress> speakersAddr;
|
Map<Integer,SocketAddress> speakersAddr;
|
||||||
Map<Integer,List<Integer>> listening; // micId, List<speakerId>
|
Map<Integer,List<Integer>> listening; // micId, List<speakerId>
|
||||||
|
|
||||||
private Set<Runnable> changeListeners;
|
public AudioServer() {
|
||||||
private Set<Consumer<Exception>> serverErrorException;
|
|
||||||
|
|
||||||
public AudioServer(GameManager manager) throws SocketException, UnknownHostException {
|
|
||||||
mics = new HashMap<Integer, String>();
|
mics = new HashMap<Integer, String>();
|
||||||
micsAddr = new HashMap<Integer, SocketAddress>();
|
micsAddr = new HashMap<Integer, SocketAddress>();
|
||||||
speakers = new HashMap<Integer, String>();
|
speakers = new HashMap<Integer, String>();
|
||||||
speakersAddr = new HashMap<Integer, SocketAddress>();
|
speakersAddr = new HashMap<Integer, SocketAddress>();
|
||||||
listening = new HashMap<Integer, List<Integer>>();
|
listening = new HashMap<Integer, List<Integer>>();
|
||||||
|
|
||||||
changeListeners = new HashSet<>();
|
|
||||||
serverErrorException = new HashSet<>();
|
|
||||||
|
|
||||||
gameInterface = new GameNetworkInterface(manager, this);
|
|
||||||
|
|
||||||
|
try {
|
||||||
initServer();
|
initServer();
|
||||||
}
|
} catch (SocketException | UnknownHostException e) {
|
||||||
|
|
||||||
public AudioServer(GameManager manager, YamlMapping data) throws SocketException, UnknownHostException {
|
|
||||||
this(manager);
|
|
||||||
for(YamlNode spkn : data.yamlMapping("enceintes").values()) {
|
|
||||||
try {
|
|
||||||
YamlMapping spk = spkn.asMapping();
|
|
||||||
int id = spk.integer("id");
|
|
||||||
String name = spk.string("name");
|
|
||||||
SocketAddress address = (SocketAddress) ParseUtils.fromBase64(spk.string("address"));
|
|
||||||
speakers.put(id, name);
|
|
||||||
speakersAddr.put(id, address);
|
|
||||||
} catch (ClassNotFoundException e) {
|
|
||||||
System.err.println("Impossible de récupérer l'adresse de cette enceinte");
|
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for(YamlNode micn : data.yamlMapping("micros").values()) {
|
|
||||||
try {
|
|
||||||
YamlMapping mic = micn.asMapping();
|
|
||||||
int id = mic.integer("id");
|
|
||||||
String name = mic.string("name");
|
|
||||||
SocketAddress address = (SocketAddress) ParseUtils.fromBase64(mic.string("address"));
|
|
||||||
mics.put(id, name);
|
|
||||||
micsAddr.put(id, address);
|
|
||||||
listening.put(id, new ArrayList<>());
|
|
||||||
|
|
||||||
for(YamlNode ecId : mic.yamlSequence("listening").values()) {
|
|
||||||
listening.get(id).add(Integer.parseInt(ecId.asScalar().value()));
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (ClassNotFoundException e) {
|
|
||||||
System.err.println("Impossible de récupérer l'adresse de ce micro");
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
micId = mics.keySet().stream().collect(Collectors.maxBy(Integer::compare)).orElse(-1)+1;
|
|
||||||
speakerId = speakers.keySet().stream().collect(Collectors.maxBy(Integer::compare)).orElse(-1)+1;
|
|
||||||
|
|
||||||
|
|
||||||
publishAudioList(speakersAddr.values());
|
|
||||||
changeListeners.forEach(Runnable::run);
|
|
||||||
|
|
||||||
//XXX: Ajouter des tests demandant si toutes les enceintes sont toujours connéctées
|
|
||||||
// et savoir quel micro est connécté.
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void initServer() throws SocketException, UnknownHostException {
|
public void initServer() throws SocketException, UnknownHostException {
|
||||||
serveur = new Serveur(this::receiveCommand, Codes.communicationPort);
|
serveur = new Serveur(this::receiveCommand, AudioServer.communicationPort);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void receiveCommand(ByteBuffer data,SocketAddress senderAddress) {
|
public void receiveCommand(ByteBuffer data,SocketAddress senderAddress) {
|
||||||
byte commande = data.get();
|
byte commande = data.get();
|
||||||
System.out.println("Commande reçue : "+commande+" de "+senderAddress+" de taille "+(data.limit()+1));
|
System.out.println("Commande reçue : "+commande);
|
||||||
switch (commande) {
|
switch (commande) {
|
||||||
|
|
||||||
case Codes.DECLARE_NUMBER:
|
case AudioServer.DECLARE_NUMBER:
|
||||||
|
|
||||||
UUID uuid = new UUID(data.getLong(), data.getLong());
|
UUID uuid = new UUID(data.getLong(), data.getLong());
|
||||||
byte deviceType = data.get();
|
byte deviceType = data.get();
|
||||||
String deviceName = BytesUtils.readString(data);
|
String deviceName = BytesUtils.readString(data);
|
||||||
int newId;
|
int newId;
|
||||||
switch (deviceType) {
|
switch (deviceType) {
|
||||||
case Codes.Device.MIC_DEVICE:
|
case AudioServer.MIC_DEVICE:
|
||||||
newId = micId++;
|
newId = micId++;
|
||||||
mics.put(newId, deviceName);
|
mics.put(newId, deviceName);
|
||||||
micsAddr.put(newId, senderAddress);
|
micsAddr.put(newId, senderAddress);
|
||||||
listening.put(newId, new ArrayList<>());
|
listening.put(newId, new ArrayList<>());
|
||||||
publishAudioList(speakersAddr.values());
|
|
||||||
break;
|
break;
|
||||||
case Codes.Device.SPEAKER_DEVICE:
|
case AudioServer.SPEAKER_DEVICE:
|
||||||
newId = speakerId++;
|
newId = speakerId++;
|
||||||
speakers.put(newId, deviceName);
|
speakers.put(newId, deviceName);
|
||||||
speakersAddr.put(newId, senderAddress);
|
speakersAddr.put(newId, senderAddress);
|
||||||
break;
|
break;
|
||||||
default:return;
|
default:return;
|
||||||
}
|
}
|
||||||
ByteBuffer out = ByteBuffer.allocate(Codes.packetMaxSize);
|
ByteBuffer out = ByteBuffer.allocate(AudioServer.packetMaxSize);
|
||||||
out.put(Codes.OK_ID);
|
out.put(AudioServer.OK_ID);
|
||||||
out.putLong(uuid.getMostSignificantBits());
|
out.putLong(uuid.getMostSignificantBits());
|
||||||
out.putLong(uuid.getLeastSignificantBits());
|
out.putLong(uuid.getLeastSignificantBits());
|
||||||
out.put(deviceType);
|
out.put(deviceType);
|
||||||
@ -157,353 +112,71 @@ public class AudioServer {
|
|||||||
} catch (IOException e1) {
|
} catch (IOException e1) {
|
||||||
e1.printStackTrace();
|
e1.printStackTrace();
|
||||||
}
|
}
|
||||||
changeListeners.forEach(Runnable::run);
|
|
||||||
System.out.println("Accepting request from "+senderAddress);
|
|
||||||
break;
|
break;
|
||||||
case Codes.ASK_STREAMING:
|
case AudioServer.ASK_STREAMING:
|
||||||
int listened = data.getInt();
|
int listened = data.getInt();
|
||||||
int listener = data.getInt();
|
int listener = data.getInt();
|
||||||
|
listening.get(listened).add(listener);
|
||||||
if(listening.get(listened).contains(listener))
|
ByteBuffer out3 = ByteBuffer.allocate(AudioServer.packetMaxSize);
|
||||||
break;
|
out3.put(AudioServer.START_STREAMING);
|
||||||
|
|
||||||
ByteBuffer out3 = ByteBuffer.allocate(Codes.packetMaxSize);
|
|
||||||
out3.put(Codes.START_STREAMING);
|
|
||||||
out3.putInt(listened);
|
out3.putInt(listened);
|
||||||
try {
|
try {
|
||||||
serveur.sendData(out3, micsAddr.get(listened));
|
serveur.sendData(out3, micsAddr.get(listened));
|
||||||
|
|
||||||
listening.get(listened).add(listener);
|
|
||||||
changeListeners.forEach(Runnable::run);
|
|
||||||
} catch (IOException e2) {
|
} catch (IOException e2) {
|
||||||
e2.printStackTrace();
|
e2.printStackTrace();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Codes.ASK_STOP_STREAMING:
|
case AudioServer.STOP_STREAMING:
|
||||||
int listened2 = data.getInt();
|
int listened2 = data.getInt();
|
||||||
int listener2 = data.getInt();
|
int listener2 = data.getInt();
|
||||||
if(listened2==-1)break;
|
listening.get(listener2).remove(listened2);
|
||||||
try{
|
ByteBuffer out4 = ByteBuffer.allocate(AudioServer.packetMaxSize);
|
||||||
listening.get(listened2).remove(listener2);
|
out4.put(AudioServer.STOP_STREAMING);
|
||||||
}catch(IndexOutOfBoundsException e) {
|
|
||||||
System.err.println("Les données enregistrées par ce serveur ne sont pas intègres !");
|
|
||||||
}
|
|
||||||
changeListeners.forEach(Runnable::run);
|
|
||||||
|
|
||||||
if(listening.get(listened2).isEmpty()) {
|
|
||||||
try {
|
|
||||||
ByteBuffer out4 = ByteBuffer.allocate(Codes.packetMaxSize);
|
|
||||||
out4.put(Codes.STOP_STREAMING);
|
|
||||||
out4.putInt(listened2);
|
out4.putInt(listened2);
|
||||||
|
try {
|
||||||
serveur.sendData(out4, micsAddr.get(listened2));
|
serveur.sendData(out4, micsAddr.get(listened2));
|
||||||
|
|
||||||
} catch (IOException e2) {
|
} catch (IOException e2) {
|
||||||
e2.printStackTrace();
|
e2.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Codes.AUDIO_STREAM:
|
case AudioServer.AUDIO_STREAM:
|
||||||
int micId = data.getInt();
|
int micId = data.getInt();
|
||||||
data.position(data.limit());
|
byte[] audioData = new byte[data.remaining()];
|
||||||
|
data.get(audioData);
|
||||||
|
|
||||||
|
|
||||||
for(int spck : listening.get(micId)) {
|
for(int spck : listening.get(micId)) {
|
||||||
|
data.clear();
|
||||||
SocketAddress dest = speakersAddr.get(spck);
|
SocketAddress dest = speakersAddr.get(spck);
|
||||||
try {
|
try {
|
||||||
serveur.sendData(data, dest);
|
serveur.sendData(data, dest);
|
||||||
} catch (IOException e1) {
|
} catch (IOException e1) {
|
||||||
e1.printStackTrace();
|
e1.printStackTrace();
|
||||||
JOptionPane.showMessageDialog(null, "Impossible de transmettre le son !","Son impossible !",JOptionPane.ERROR_MESSAGE);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
case Codes.ASK_AUDIO_LIST:
|
case AudioServer.ASK_AUDIO_LIST:
|
||||||
|
ByteBuffer out2 = ByteBuffer.allocate(AudioServer.packetMaxSize);
|
||||||
System.out.println("Sending audio list to "+senderAddress+" : ");
|
out2.put(AudioServer.GIVE_AUDIO_LIST);
|
||||||
publishAudioList(Collections.singleton(senderAddress));
|
out2.putInt(mics.size());
|
||||||
|
for(Entry<Integer, String> e : mics.entrySet()) {
|
||||||
break;
|
out2.putInt(e.getKey());
|
||||||
|
BytesUtils.writeString(out2, e.getValue());
|
||||||
case Codes.DISCONNECTING:
|
|
||||||
byte deviceType2 = data.get();
|
|
||||||
int deviceId = data.getInt();
|
|
||||||
if(deviceType2==Codes.Device.MIC_DEVICE) {
|
|
||||||
// On le déréférence
|
|
||||||
if(!mics.containsKey(deviceId)) {
|
|
||||||
System.out.println("Le micro d'id "+deviceId+" est déjà désinscrit");
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
System.out.println("Déconnection du microphone "+mics.get(deviceId));
|
|
||||||
mics.remove(deviceId);
|
|
||||||
micsAddr.remove(deviceId);
|
|
||||||
changeListeners.forEach(Runnable::run);
|
|
||||||
|
|
||||||
// On enlève tous les liens d'écoute
|
|
||||||
for(int spkId : listening.get(deviceId)) {
|
|
||||||
// Annoncer à ce speaker que le micro est déconnécté et qu'il ne peut plus l'écouter.
|
|
||||||
ByteBuffer out5 = ByteBuffer.allocate(Codes.packetMaxSize);
|
|
||||||
out5.put(Codes.DISCONNECTING);
|
|
||||||
out5.put(Codes.Device.MIC_DEVICE);
|
|
||||||
out5.putInt(deviceId);
|
|
||||||
try {
|
try {
|
||||||
serveur.sendData(out5, speakersAddr.get(spkId));
|
serveur.sendData(out2, senderAddress);
|
||||||
} catch (IOException e1) {
|
} catch (IOException e1) {
|
||||||
e1.printStackTrace();
|
e1.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
listening.remove(deviceId);
|
|
||||||
publishAudioList(speakersAddr.values());
|
|
||||||
|
|
||||||
}else if(deviceType2==Codes.Device.SPEAKER_DEVICE) {
|
|
||||||
|
|
||||||
// On le déréférence
|
|
||||||
System.out.println("Déconnection de l'enceinte "+speakers.get(deviceId));
|
|
||||||
speakers.remove(deviceId);
|
|
||||||
speakersAddr.remove(deviceId);
|
|
||||||
changeListeners.forEach(Runnable::run);
|
|
||||||
|
|
||||||
int lstTo = listens(deviceId);
|
|
||||||
if(lstTo!=-1) {
|
|
||||||
// On enlève le lien d'écoute
|
|
||||||
listening.get(lstTo).remove((Integer)deviceId);
|
|
||||||
|
|
||||||
if(listening.get(lstTo).isEmpty()) {
|
|
||||||
// Si il n'y a plus rien à écouter.
|
|
||||||
try {
|
|
||||||
ByteBuffer out4 = ByteBuffer.allocate(Codes.packetMaxSize);
|
|
||||||
out4.put(Codes.STOP_STREAMING);
|
|
||||||
out4.putInt(lstTo);
|
|
||||||
serveur.sendData(out4, micsAddr.get(lstTo));
|
|
||||||
} catch (IOException e1) {
|
|
||||||
e1.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}else {
|
|
||||||
System.err.println("Je ne sais pas comment réagir à la déconnection d'un appareil de type "+deviceType2);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Codes.PING:
|
|
||||||
ByteBuffer outPong = ByteBuffer.allocate(Codes.packetMaxSize);
|
|
||||||
outPong.put(Codes.PONG);
|
|
||||||
try {
|
|
||||||
serveur.sendData(outPong, senderAddress);
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Codes.ACCES_PARTIE:
|
|
||||||
// On délègue
|
|
||||||
gameInterface.receiveCommand(data, senderAddress);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
System.out.println("Je ne devait pas recevoir cette commade !");
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addChangeListener(Runnable listener) {
|
|
||||||
changeListeners.add(listener);
|
|
||||||
}
|
|
||||||
public void removeChangeListener(Runnable listener) {
|
|
||||||
changeListeners.remove(listener);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<Integer, String> getMics() {
|
|
||||||
return Collections.unmodifiableMap(mics);
|
|
||||||
}
|
|
||||||
public Map<Integer, String> getSpeakers() {
|
|
||||||
return Collections.unmodifiableMap(speakers);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int listens(int spk) {
|
|
||||||
for(int mic : listening.keySet()) {
|
|
||||||
if(listening.get(mic).contains(spk))
|
|
||||||
return mic;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void publishAudioList(Collection<SocketAddress> to) {
|
|
||||||
ByteBuffer out = ByteBuffer.allocate(Codes.packetMaxSize);
|
|
||||||
out.put(Codes.GIVE_AUDIO_LIST);
|
|
||||||
out.putInt(mics.size());
|
|
||||||
for(Entry<Integer, String> mic : mics.entrySet()) {
|
|
||||||
out.putInt(mic.getKey());
|
|
||||||
BytesUtils.writeString(out, mic.getValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
for(SocketAddress addr : to) {
|
|
||||||
try {
|
|
||||||
serveur.sendData(out, addr);
|
|
||||||
} catch (Exception e) {
|
|
||||||
serverErrorException.forEach(c -> c.accept(e));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int enceinteIdFromName(String name) {
|
|
||||||
for(int i:speakers.keySet()) {
|
|
||||||
if(name.equalsIgnoreCase(speakers.get(i)))
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void forceSilence(int id) {
|
|
||||||
if(!speakers.containsKey(id))
|
|
||||||
return;
|
|
||||||
|
|
||||||
int lstTo = listens(id);
|
|
||||||
if(lstTo!=-1) {
|
|
||||||
// On enlève le lien d'écoute
|
|
||||||
listening.get(lstTo).remove(id);
|
|
||||||
|
|
||||||
// Si il n'y a plus rien à écouter.
|
|
||||||
ByteBuffer out4 = ByteBuffer.allocate(Codes.packetMaxSize);
|
|
||||||
out4.put(Codes.STOP_STREAMING);
|
|
||||||
out4.putInt(lstTo);
|
|
||||||
try {
|
|
||||||
serveur.sendData(out4, speakersAddr.get(id));
|
|
||||||
} catch (Exception e1) {
|
|
||||||
serverErrorException.forEach(c -> c.accept(e1));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void disconnectEnceinte(int id) {
|
|
||||||
|
|
||||||
if(!speakers.containsKey(id))
|
|
||||||
return;
|
|
||||||
// On lui annonce notre déconnection, puis on la supprime des données
|
|
||||||
ByteBuffer decoBuf = ByteBuffer.allocate(Codes.packetMaxSize);
|
|
||||||
decoBuf.put(Codes.DISCONNECTING);
|
|
||||||
decoBuf.put(Codes.Device.MASTER_DEVICE);
|
|
||||||
decoBuf.putInt(0);
|
|
||||||
try {
|
|
||||||
serveur.sendData(decoBuf, speakersAddr.get(id));
|
|
||||||
} catch (Exception e) {
|
|
||||||
serverErrorException.forEach(c -> c.accept(e));
|
|
||||||
}
|
|
||||||
|
|
||||||
speakers.remove(id);
|
|
||||||
speakersAddr.remove(id);
|
|
||||||
changeListeners.forEach(Runnable::run);
|
|
||||||
|
|
||||||
int lstTo = listens(id);
|
|
||||||
if(lstTo!=-1) {
|
|
||||||
// On enlève le lien d'écoute
|
|
||||||
listening.get(lstTo).remove(id);
|
|
||||||
|
|
||||||
if(listening.get(lstTo).isEmpty()) {
|
|
||||||
// Si il n'y a plus rien à écouter.
|
|
||||||
ByteBuffer out4 = ByteBuffer.allocate(Codes.packetMaxSize);
|
|
||||||
out4.put(Codes.STOP_STREAMING);
|
|
||||||
out4.putInt(lstTo);
|
|
||||||
try {
|
|
||||||
serveur.sendData(out4, micsAddr.get(lstTo));
|
|
||||||
} catch (Exception e1) {
|
|
||||||
serverErrorException.forEach(c -> c.accept(e1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void disconnectMic(int id) {
|
|
||||||
|
|
||||||
if(!mics.containsKey(id))
|
|
||||||
return;
|
|
||||||
// On lui annonce notre déconnection, puis on la supprime des données
|
|
||||||
ByteBuffer decoBuf = ByteBuffer.allocate(Codes.packetMaxSize);
|
|
||||||
decoBuf.put(Codes.DISCONNECTING);
|
|
||||||
decoBuf.put(Codes.Device.MASTER_DEVICE);
|
|
||||||
decoBuf.putInt(0);
|
|
||||||
try {
|
|
||||||
serveur.sendData(decoBuf, micsAddr.get(id));
|
|
||||||
} catch (Exception e) {
|
|
||||||
serverErrorException.forEach(c -> c.accept(e));
|
|
||||||
}
|
|
||||||
|
|
||||||
mics.remove(id);
|
|
||||||
micsAddr.remove(id);
|
|
||||||
changeListeners.forEach(Runnable::run);
|
|
||||||
|
|
||||||
for(int lster : listening.get(id)) {
|
|
||||||
ByteBuffer out4 = ByteBuffer.allocate(Codes.packetMaxSize);
|
|
||||||
out4.put(Codes.STOP_STREAMING);
|
|
||||||
out4.putInt(id);
|
|
||||||
try {
|
|
||||||
serveur.sendData(out4, speakersAddr.get(lster));
|
|
||||||
} catch (Exception e1) {
|
|
||||||
serverErrorException.forEach(c -> c.accept(e1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
publishAudioList(listening.get(id).stream().map(speakersAddr::get).collect(Collectors.toSet()));
|
|
||||||
listening.remove(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void dispose() {
|
|
||||||
speakers.keySet().forEach(this::disconnectEnceinte);
|
|
||||||
mics.keySet().forEach(this::disconnectMic);
|
|
||||||
|
|
||||||
mics.clear();
|
|
||||||
speakers.clear();
|
|
||||||
micsAddr.clear();
|
|
||||||
speakersAddr.clear();
|
|
||||||
listening.clear();
|
|
||||||
|
|
||||||
changeListeners.forEach(Runnable::run);
|
|
||||||
|
|
||||||
serveur.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
public YamlMapping saveToYaml() {
|
|
||||||
YamlSequenceBuilder ymbMics = Yaml.createYamlSequenceBuilder();
|
|
||||||
for(int i : mics.keySet()) {
|
|
||||||
ymbMics = ymbMics.add(
|
|
||||||
Yaml.createYamlMappingBuilder()
|
|
||||||
.add("id", Integer.toString(i))
|
|
||||||
.add("name", mics.get(i))
|
|
||||||
.add("address", ParseUtils.toBase64(micsAddr.get(i)))
|
|
||||||
.add("listening", listening.get(i)
|
|
||||||
.stream()
|
|
||||||
.map(YamlUtils::scalar)
|
|
||||||
.collect(YamlUtils.sequenceCollector))
|
|
||||||
.build());
|
|
||||||
}
|
|
||||||
|
|
||||||
YamlSequenceBuilder ymbSpks = Yaml.createYamlSequenceBuilder();
|
|
||||||
for(int i : speakers.keySet()) {
|
|
||||||
ymbSpks = ymbSpks.add(
|
|
||||||
Yaml.createYamlMappingBuilder()
|
|
||||||
.add("id", Integer.toString(i))
|
|
||||||
.add("name", speakers.get(i))
|
|
||||||
.add("address", ParseUtils.toBase64(speakersAddr.get(i)))
|
|
||||||
.build());
|
|
||||||
}
|
|
||||||
|
|
||||||
return Yaml.createYamlMappingBuilder()
|
|
||||||
.add("micros", ymbMics.build())
|
|
||||||
.add("enceintes", ymbSpks.build())
|
|
||||||
.build();
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void genPasswords() { //XXX : Refaire ce système avec considération pour les OPés aussi ^^
|
|
||||||
for(Personnage perso : gameInterface.theManager.partie().personnages()) {
|
|
||||||
byte[] tokenBytes = new byte[6];
|
|
||||||
ThreadLocalRandom.current().nextBytes(tokenBytes);
|
|
||||||
String pass = Base64.getUrlEncoder().encodeToString(tokenBytes);
|
|
||||||
pass = "bb";
|
|
||||||
gameInterface.addPass(perso.getNom(),pass);
|
|
||||||
System.out.println("Mdp de "+perso.getNom()+": "+pass);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,101 +0,0 @@
|
|||||||
package com.bernard.murder.audio;
|
|
||||||
|
|
||||||
public class Codes {
|
|
||||||
|
|
||||||
public static class Device{
|
|
||||||
public static final byte MASTER_DEVICE = 0x42;
|
|
||||||
public static final byte SPEAKER_DEVICE = 0x01;
|
|
||||||
public static final byte MIC_DEVICE = 0x02;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int packetMaxSize = 97282;
|
|
||||||
public static int communicationPort = 35295;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Format des paquets [commande 1, UUID identifier, byte deviceType, String name]
|
|
||||||
public static final byte DECLARE_NUMBER = 0x02;
|
|
||||||
// Format des paquets [commande 1, UUID identifier, byte deviceType, int id]
|
|
||||||
public static final byte OK_ID = 0x03;
|
|
||||||
// Format des paquets [commande 1]
|
|
||||||
public static final byte ASK_AUDIO_LIST= 0x04;
|
|
||||||
// Format des paquets [commande 1, int Count, {int id, String name}]
|
|
||||||
public static final byte GIVE_AUDIO_LIST = 0x05;
|
|
||||||
// Format des paquets: [commande 1, int listenId, int myId]
|
|
||||||
// -> Une enceinte demande à master le son d'un micro
|
|
||||||
public static final byte ASK_STREAMING = 0x06;
|
|
||||||
// Format des paquets: [commande 1, int id]
|
|
||||||
// -> Master demande à un micro d'envoyer du son
|
|
||||||
public static final byte START_STREAMING = 0x07;
|
|
||||||
// Format des paquets: [commande 1, int listenId, int myId]e.printStackTrace();
|
|
||||||
// -> Une enceinte demande à master de ne plus recevoir le son d'un micro
|
|
||||||
public static final byte ASK_STOP_STREAMING = 0x09;
|
|
||||||
// Format des paquets: [commande 1, int id]
|
|
||||||
// -> Master demande à un micro de ne plus émettre.
|
|
||||||
// -> Master annonce à une enceinte qu'il n'emmet plus le micro demandé.
|
|
||||||
public static final byte STOP_STREAMING = 0x08;
|
|
||||||
// Format des paquets [commande 1, int id, ~ data]
|
|
||||||
public static final byte AUDIO_STREAM = 0x01;
|
|
||||||
// Format des paquets [commande 1, byte deviceType, int deviceId]
|
|
||||||
// Un terminal indique qu'il se ferme à la connection
|
|
||||||
public static final byte DISCONNECTING = 0x0A;
|
|
||||||
|
|
||||||
// Envoie la commande au gamemanager afin que la commande accède à la partie.
|
|
||||||
public static final byte ACCES_PARTIE = 0x2A;
|
|
||||||
|
|
||||||
public static final byte PING = 0x3A;
|
|
||||||
public static final byte PONG = 0x3B;
|
|
||||||
|
|
||||||
|
|
||||||
public static class Partie {
|
|
||||||
// [ACCÈS_PARTIE, commandePartie 1, String opName, String mdp]
|
|
||||||
public static final byte ASK_OP_TOKEN = 0x71;
|
|
||||||
// [ACCÈS_PARTIE, commandePartie 1, String joueurName, String mdp]
|
|
||||||
public static final byte ASK_JOUEUR_TOKEN = 0x72;
|
|
||||||
// [ACCÈS_PARTIE, commandePartie 1, String token]
|
|
||||||
public static final byte GIVING_TOKEN = 0x73;
|
|
||||||
// [ACCÈS_PARTIE, commandePartie 1, String token]
|
|
||||||
public static final byte AUTH_ERROR = 0x75;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//Entête de tous le paquets: [ACCÈS_PARTIE, commandePartie 1]
|
|
||||||
|
|
||||||
// [] (pas besoin du token)
|
|
||||||
public static final byte ASK_PLAYER_LIST = 0x01;
|
|
||||||
// [int nombreDeJoueurs, nombreDeJoueurs*String joueursNames]
|
|
||||||
public static final byte GIVE_PLAYER_LIST = 0x02;
|
|
||||||
|
|
||||||
// [String token, String inventoryName]
|
|
||||||
public static final byte ASK_INVENTORY = 0x03;
|
|
||||||
// [String token, String inventoryName]
|
|
||||||
public static final byte ASK_INVENTORY_WATCH = 0x04;
|
|
||||||
// [String inventoryName, int objCount, objCount*String objNames]
|
|
||||||
public static final byte INVENTORY_CONTENT = 0x05;
|
|
||||||
|
|
||||||
// [String token, String persoName]
|
|
||||||
public static final byte ASK_ACTIONS = 0x06;
|
|
||||||
// [String token, String persoName]
|
|
||||||
public static final byte ASK_ACTIONS_WATCH = 0x07;
|
|
||||||
// [String persoName, int actionCount, (String actionName, long basetime, long triggertime)*actionCount]
|
|
||||||
public static final byte ACTIONS_STATUS = 0x08;
|
|
||||||
|
|
||||||
// [String token, UUID askCode, long startTimestamp]
|
|
||||||
public static final byte ASK_NEW_THREAD = 0x09;
|
|
||||||
// [UUID askCode, String persoName, long uid, long startTimestamp]
|
|
||||||
public static final byte CREATED_NEW_THREAD = 0x0A;
|
|
||||||
/// [String token, long uid, long closeTimestamp]
|
|
||||||
public static final byte CLOSE_NEW_THREAD = 0x0B;
|
|
||||||
// [long uid, long closeTimestamp]
|
|
||||||
public static final byte CLOSED_THREAD = 0x0C;
|
|
||||||
// [String token, long sendTimestamp, @Nullable long threadUid, String emmeteur, String texte]
|
|
||||||
public static final byte SEND_MESSAGE = 0x0D;
|
|
||||||
// [long sendTimestamp, @Nullable long threadUid, @Nullable int threadPosition, String emmeteur, String texte]
|
|
||||||
public static final byte NEW_MESSAGE = 0x0D;
|
|
||||||
|
|
||||||
// [String token, long threadUid, @Nullable String op]
|
|
||||||
public static final byte ASK_ASSIGNATION = 0x10;
|
|
||||||
// [String token, long threadUid, @Nulalble String newOp]
|
|
||||||
public static final byte CREATED_ASSIGNATION = 0x11;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -5,14 +5,12 @@ import java.net.SocketAddress;
|
|||||||
import java.net.SocketException;
|
import java.net.SocketException;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import javax.sound.sampled.LineUnavailableException;
|
import javax.sound.sampled.LineUnavailableException;
|
||||||
import javax.sound.sampled.TargetDataLine;
|
import javax.sound.sampled.TargetDataLine;
|
||||||
|
|
||||||
import com.bernard.util.BytesUtils;
|
import com.bernard.murder.BytesUtils;
|
||||||
|
|
||||||
public class MicServer {
|
public class MicServer {
|
||||||
|
|
||||||
@ -36,14 +34,11 @@ public class MicServer {
|
|||||||
|
|
||||||
Runnable serverAnswered;
|
Runnable serverAnswered;
|
||||||
|
|
||||||
Set<Runnable> disconnectListener;
|
|
||||||
|
|
||||||
|
|
||||||
public MicServer(SocketAddress adresse,String micName,TargetDataLine tdl) {
|
public MicServer(SocketAddress adresse,String micName,TargetDataLine tdl) {
|
||||||
this.micName = micName;
|
this.micName = micName;
|
||||||
this.masterAddress = adresse;
|
this.masterAddress = adresse;
|
||||||
this.micLine = tdl;
|
this.micLine = tdl;
|
||||||
this.disconnectListener = new HashSet<>();
|
|
||||||
try {
|
try {
|
||||||
initServer();
|
initServer();
|
||||||
initializeAudioId();
|
initializeAudioId();
|
||||||
@ -56,23 +51,22 @@ public class MicServer {
|
|||||||
public void initializeMicDevice() throws LineUnavailableException {
|
public void initializeMicDevice() throws LineUnavailableException {
|
||||||
micLine.open(AudioServer.formatAudio);
|
micLine.open(AudioServer.formatAudio);
|
||||||
packetLength = micLine.getBufferSize()/5;
|
packetLength = micLine.getBufferSize()/5;
|
||||||
System.out.println("Longueur du paquet: "+packetLength);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void initServer() throws SocketException, UnknownHostException {
|
public void initServer() throws SocketException, UnknownHostException {
|
||||||
serveur = new Serveur(this::receiveCommand, Codes.communicationPort);
|
serveur = new Serveur(this::receiveCommand, AudioServer.communicationPort);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void initializeAudioId() {
|
public void initializeAudioId() {
|
||||||
ByteBuffer buffer = ByteBuffer.allocate(Codes.packetMaxSize);
|
ByteBuffer buffer = ByteBuffer.allocate(AudioServer.packetMaxSize);
|
||||||
|
|
||||||
|
|
||||||
askedUUID = UUID.randomUUID();
|
askedUUID = UUID.randomUUID();
|
||||||
|
|
||||||
buffer.put(Codes.DECLARE_NUMBER);
|
buffer.put(AudioServer.DECLARE_NUMBER);
|
||||||
buffer.putLong(askedUUID.getMostSignificantBits());
|
buffer.putLong(askedUUID.getMostSignificantBits());
|
||||||
buffer.putLong(askedUUID.getLeastSignificantBits());
|
buffer.putLong(askedUUID.getLeastSignificantBits());
|
||||||
buffer.put(Codes.Device.MIC_DEVICE);
|
buffer.put(AudioServer.MIC_DEVICE);
|
||||||
|
|
||||||
BytesUtils.writeString(buffer, micName);
|
BytesUtils.writeString(buffer, micName);
|
||||||
|
|
||||||
@ -85,36 +79,33 @@ public class MicServer {
|
|||||||
|
|
||||||
public void receiveCommand(ByteBuffer data) {
|
public void receiveCommand(ByteBuffer data) {
|
||||||
byte commande = data.get();
|
byte commande = data.get();
|
||||||
System.out.println("Commande reçue : "+commande);
|
|
||||||
switch (commande) {
|
switch (commande) {
|
||||||
|
|
||||||
case Codes.START_STREAMING:
|
case AudioServer.START_STREAMING:
|
||||||
int askedMicId = data.getInt();
|
int micId = data.getInt();
|
||||||
if(askedMicId != this.micId)return;
|
if(micId != this.micId)return;
|
||||||
shouldStream = true;
|
shouldStream = true;
|
||||||
micLine.start();
|
|
||||||
launchDataStream();
|
launchDataStream();
|
||||||
break;
|
break;
|
||||||
case Codes.STOP_STREAMING:
|
case AudioServer.STOP_STREAMING:
|
||||||
int askedMicId2 = data.getInt();
|
int micId2 = data.getInt();
|
||||||
if(askedMicId2 != this.micId)return;
|
if(micId2 != this.micId)return;
|
||||||
shouldStream = false;
|
shouldStream = false;
|
||||||
micLine.stop();
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Codes.OK_ID:
|
case AudioServer.OK_ID:
|
||||||
UUID uuid = new UUID(data.getLong(), data.getLong());
|
UUID uuid = new UUID(data.getLong(), data.getLong());
|
||||||
byte deviceType = data.get();
|
byte deviceType = data.get();
|
||||||
int deviceId = data.getInt();
|
int deviceId = data.getInt();
|
||||||
|
|
||||||
if(!askedUUID.equals(uuid) || deviceType!=Codes.Device.MIC_DEVICE)
|
if(!askedUUID.equals(uuid) || deviceType!=AudioServer.MIC_DEVICE)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this.micId = deviceId;
|
micId = deviceId;
|
||||||
|
|
||||||
new Thread(serverAnswered).start();
|
serverAnswered.run();
|
||||||
|
|
||||||
if(!micLine.isOpen())
|
if(micLine==null)
|
||||||
try {
|
try {
|
||||||
initializeMicDevice();
|
initializeMicDevice();
|
||||||
} catch (LineUnavailableException e) {
|
} catch (LineUnavailableException e) {
|
||||||
@ -122,18 +113,7 @@ public class MicServer {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Codes.DISCONNECTING:
|
|
||||||
byte deviceType2 = data.get();
|
|
||||||
if(deviceType2==Codes.Device.MASTER_DEVICE) {
|
|
||||||
System.out.println("Le master s'est déconnécté, on fait de même !");
|
|
||||||
masterAddress=null;
|
|
||||||
this.dispose();
|
|
||||||
disconnectListener.forEach(Runnable::run);
|
|
||||||
}else {
|
|
||||||
System.out.println("Un appareil de type "+deviceType2+" s'est déconécté, mais je m'en fout ^^");
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
System.out.println("Je ne devait pas recevoir cette commade !");
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -143,10 +123,8 @@ public class MicServer {
|
|||||||
streamingThread = new Thread(()->{
|
streamingThread = new Thread(()->{
|
||||||
byte[] packetData = new byte[1+4+packetLength];
|
byte[] packetData = new byte[1+4+packetLength];
|
||||||
ByteBuffer audioPacket = ByteBuffer.wrap(packetData);
|
ByteBuffer audioPacket = ByteBuffer.wrap(packetData);
|
||||||
audioPacket.put(Codes.AUDIO_STREAM);
|
audioPacket.put(AudioServer.AUDIO_STREAM);
|
||||||
audioPacket.putInt(micId);
|
audioPacket.putInt(micId);
|
||||||
audioPacket.position(audioPacket.position()+packetLength);
|
|
||||||
micLine.start();
|
|
||||||
while(shouldStream) {
|
while(shouldStream) {
|
||||||
micLine.read(packetData, 5, packetLength);
|
micLine.read(packetData, 5, packetLength);
|
||||||
try {
|
try {
|
||||||
@ -156,38 +134,17 @@ public class MicServer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
micLine.stop();
|
|
||||||
});
|
});
|
||||||
streamingThread.start();
|
streamingThread.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void dispose() {
|
public void dispose() {
|
||||||
if(masterAddress!=null) {
|
|
||||||
ByteBuffer decoPacket = ByteBuffer.allocate(Codes.packetMaxSize);
|
|
||||||
decoPacket.put(Codes.DISCONNECTING);
|
|
||||||
decoPacket.put(Codes.Device.MIC_DEVICE);
|
|
||||||
decoPacket.putInt(micId);
|
|
||||||
try {
|
|
||||||
serveur.sendData(decoPacket,masterAddress);
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
shouldStream=false;
|
|
||||||
micLine.close();
|
micLine.close();
|
||||||
serveur.close();
|
serveur.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setServerAnswered(Runnable serverAnswered) {
|
public void setServerAnswered(Runnable serverAnswered) {
|
||||||
this.serverAnswered = serverAnswered;
|
this.serverAnswered = serverAnswered;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addDisconnectListener(Runnable listener) {
|
|
||||||
disconnectListener.add(listener);
|
|
||||||
}
|
|
||||||
public void removeDisconnectListener(Runnable listener) {
|
|
||||||
disconnectListener.remove(listener);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,7 +14,7 @@ import java.util.UUID;
|
|||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import com.bernard.util.ParseUtils;
|
import com.bernard.murder.ParseUtils;
|
||||||
|
|
||||||
public class Serveur {
|
public class Serveur {
|
||||||
|
|
||||||
@ -28,21 +28,19 @@ public class Serveur {
|
|||||||
|
|
||||||
volatile boolean isReceiving = false;
|
volatile boolean isReceiving = false;
|
||||||
|
|
||||||
boolean networkOnSeparatedThread = false;
|
BiConsumer<ByteBuffer,SocketAddress> consumer;
|
||||||
|
|
||||||
BiConsumer<Object,SocketAddress> consumer; // Where object has type byte[]
|
|
||||||
|
|
||||||
public Serveur(Consumer<ByteBuffer> dataEater, int port) throws UnknownHostException, SocketException {
|
public Serveur(Consumer<ByteBuffer> dataEater, int port) throws UnknownHostException, SocketException {
|
||||||
this((o,s) -> dataEater.accept(ByteBuffer.wrap((byte[])o)),new InetSocketAddress(port));
|
this((b,i)->dataEater.accept(b),new InetSocketAddress(port));
|
||||||
}
|
}
|
||||||
public Serveur(Consumer<ByteBuffer> dataEater,SocketAddress addresse) throws UnknownHostException, SocketException {
|
public Serveur(Consumer<ByteBuffer> dataEater,SocketAddress addresse) throws UnknownHostException, SocketException {
|
||||||
this((o,s) -> dataEater.accept(ByteBuffer.wrap((byte[])o)),addresse);
|
this((b,i)->dataEater.accept(b),addresse);
|
||||||
}
|
}
|
||||||
public Serveur(BiConsumer<ByteBuffer,SocketAddress> dataEater,int port) throws UnknownHostException, SocketException {
|
public Serveur(BiConsumer<ByteBuffer,SocketAddress> dataEater,int port) throws UnknownHostException, SocketException {
|
||||||
this((o,s) -> dataEater.accept(ByteBuffer.wrap((byte[])o),s),new InetSocketAddress(port));
|
this(dataEater,new InetSocketAddress(port));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Serveur(BiConsumer<Object,SocketAddress> dataEater,SocketAddress adresse) throws SocketException {
|
public Serveur(BiConsumer<ByteBuffer,SocketAddress> dataEater,SocketAddress adresse) throws SocketException {
|
||||||
|
|
||||||
byteArrays = new HashMap<UUID, byte[]>();
|
byteArrays = new HashMap<UUID, byte[]>();
|
||||||
receivedSlicesArray = new HashMap<UUID, boolean[]>();
|
receivedSlicesArray = new HashMap<UUID, boolean[]>();
|
||||||
@ -84,14 +82,14 @@ public class Serveur {
|
|||||||
System.arraycopy(data, paquet.getOffset()+41, bigData, offset, paquet.getLength()-41);
|
System.arraycopy(data, paquet.getOffset()+41, bigData, offset, paquet.getLength()-41);
|
||||||
recievedArray[sliceId] = true;
|
recievedArray[sliceId] = true;
|
||||||
if(!ParseUtils.and(recievedArray)) {
|
if(!ParseUtils.and(recievedArray)) {
|
||||||
consumer.accept(bigData,paquet.getSocketAddress());
|
ByteBuffer dataBuffer = ByteBuffer.wrap(bigData);
|
||||||
|
consumer.accept(dataBuffer,paquet.getSocketAddress());
|
||||||
byteArrays.remove(uuid);
|
byteArrays.remove(uuid);
|
||||||
receivedSlicesArray.remove(uuid);
|
receivedSlicesArray.remove(uuid);
|
||||||
}
|
}
|
||||||
}else {
|
}else {
|
||||||
byte[] realData = new byte[paquet.getLength()];
|
ByteBuffer dataBuffer = ByteBuffer.wrap(data,paquet.getOffset(),paquet.getLength());
|
||||||
System.arraycopy(data, paquet.getOffset(), realData, 0, paquet.getLength());
|
consumer.accept(dataBuffer,paquet.getSocketAddress());
|
||||||
consumer.accept(data,paquet.getSocketAddress());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@ -100,38 +98,22 @@ public class Serveur {
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},"Receveur de paquets");
|
});
|
||||||
isReceiving = true;
|
isReceiving = true;
|
||||||
packetReceiver.start();
|
packetReceiver.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendData(ByteBuffer buffer,SocketAddress address) throws IOException {
|
public void sendData(ByteBuffer buffer,SocketAddress address) throws IOException {
|
||||||
byte[] data = new byte[buffer.position()];
|
byte[] data = new byte[buffer.position()];
|
||||||
buffer.flip();
|
buffer.clear();
|
||||||
buffer.get(data);
|
buffer.get(data);
|
||||||
sendData(data,address);
|
sendData(data,address);
|
||||||
}
|
}
|
||||||
public void sendData(byte[] data, SocketAddress address) throws IOException {
|
public void sendData(byte[] data, SocketAddress address) throws IOException {
|
||||||
if(data.length < packetMaxLength) {
|
if(data.length < packetMaxLength) {
|
||||||
DatagramPacket packet = new DatagramPacket(data, data.length,address);
|
DatagramPacket packet = new DatagramPacket(data, data.length,address);
|
||||||
if(networkOnSeparatedThread) {
|
|
||||||
Thread subLauncher = new Thread(() -> {
|
|
||||||
try {
|
|
||||||
socket.send(packet);
|
|
||||||
} catch (IOException e) {
|
|
||||||
Thread.currentThread().getUncaughtExceptionHandler().uncaughtException(Thread.currentThread(), e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
subLauncher.start();
|
|
||||||
try {
|
|
||||||
subLauncher.join();
|
|
||||||
} catch (InterruptedException e) {}
|
|
||||||
|
|
||||||
}
|
|
||||||
else
|
|
||||||
socket.send(packet);
|
socket.send(packet);
|
||||||
}else {
|
}else {
|
||||||
//XXX Ça, ca ne marche pas !
|
|
||||||
short packetCount = (short) (data.length / (packetMaxLength-42));
|
short packetCount = (short) (data.length / (packetMaxLength-42));
|
||||||
short packetLength = (short) (data.length / packetCount);
|
short packetLength = (short) (data.length / packetCount);
|
||||||
short lastPacketLength = (short) (data.length - (packetCount-1)*packetLength);
|
short lastPacketLength = (short) (data.length - (packetCount-1)*packetLength);
|
||||||
@ -167,14 +149,10 @@ public class Serveur {
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public void close() {
|
public void dispose() {
|
||||||
isReceiving = false;
|
isReceiving = false;
|
||||||
socket.close();
|
socket.close();
|
||||||
packetReceiver.interrupt();
|
packetReceiver.interrupt();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setNetworkOnSeparatedThread(boolean networkOnSeparatedThread) {
|
|
||||||
this.networkOnSeparatedThread = networkOnSeparatedThread;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,22 +6,21 @@ import java.net.SocketException;
|
|||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.function.Consumer;
|
|
||||||
|
|
||||||
import javax.sound.sampled.LineUnavailableException;
|
import javax.sound.sampled.LineUnavailableException;
|
||||||
import javax.sound.sampled.SourceDataLine;
|
import javax.sound.sampled.SourceDataLine;
|
||||||
|
|
||||||
import com.bernard.util.BytesUtils;
|
import com.bernard.murder.BytesUtils;
|
||||||
|
|
||||||
|
|
||||||
public class SpeakerServer {
|
public class SpeakerServer {
|
||||||
|
|
||||||
SourceDataLine speakerLine;
|
SourceDataLine speakerLine;
|
||||||
|
|
||||||
|
int packetLength = 9728;
|
||||||
|
|
||||||
int speakerId;
|
int speakerId;
|
||||||
|
|
||||||
String speakerName;
|
String speakerName;
|
||||||
@ -31,6 +30,7 @@ public class SpeakerServer {
|
|||||||
Serveur serveur;
|
Serveur serveur;
|
||||||
|
|
||||||
Map<Integer,String> mics;
|
Map<Integer,String> mics;
|
||||||
|
volatile boolean isMicListUpToDate = false;
|
||||||
|
|
||||||
int listeningTo = -1;
|
int listeningTo = -1;
|
||||||
|
|
||||||
@ -39,20 +39,10 @@ public class SpeakerServer {
|
|||||||
Runnable serverAnswered;
|
Runnable serverAnswered;
|
||||||
|
|
||||||
|
|
||||||
Set<Runnable> disconnectListener;
|
|
||||||
Set<Runnable> brokenMicListener;
|
|
||||||
Set<Consumer<Map<Integer, String>>> micListUpdateListener;
|
|
||||||
|
|
||||||
|
|
||||||
public SpeakerServer(SocketAddress serveur,String speakerName,SourceDataLine speaker) {
|
public SpeakerServer(SocketAddress serveur,String speakerName,SourceDataLine speaker) {
|
||||||
this.speakerName = speakerName;
|
this.speakerName = speakerName;
|
||||||
this.masterAddress = serveur;
|
this.masterAddress = serveur;
|
||||||
this.speakerLine = speaker;
|
this.speakerLine = speaker;
|
||||||
|
|
||||||
this.disconnectListener = new HashSet<>();
|
|
||||||
this.brokenMicListener = new HashSet<>();
|
|
||||||
this.micListUpdateListener = new HashSet<>();
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
initServer();
|
initServer();
|
||||||
initializeAudioId();
|
initializeAudioId();
|
||||||
@ -62,24 +52,24 @@ public class SpeakerServer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void initServer() throws SocketException, UnknownHostException {
|
public void initServer() throws SocketException, UnknownHostException {
|
||||||
serveur = new Serveur(this::receiveCommand,Codes.communicationPort);
|
serveur = new Serveur(this::receiveCommand,AudioServer.communicationPort);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void initializeSpeakerDevice() throws LineUnavailableException {
|
public void initializeSpeakerDevice() throws LineUnavailableException {
|
||||||
speakerLine.open(AudioServer.formatAudio);
|
speakerLine.open(AudioServer.formatAudio);
|
||||||
speakerLine.start();
|
packetLength = speakerLine.getBufferSize()/5;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void initializeAudioId() {
|
public void initializeAudioId() {
|
||||||
ByteBuffer buffer = ByteBuffer.allocate(Codes.packetMaxSize);
|
ByteBuffer buffer = ByteBuffer.allocate(AudioServer.packetMaxSize);
|
||||||
|
|
||||||
|
|
||||||
askedUUID = UUID.randomUUID();
|
askedUUID = UUID.randomUUID();
|
||||||
|
|
||||||
buffer.put(Codes.DECLARE_NUMBER);
|
buffer.put(AudioServer.DECLARE_NUMBER);
|
||||||
buffer.putLong(askedUUID.getMostSignificantBits());
|
buffer.putLong(askedUUID.getMostSignificantBits());
|
||||||
buffer.putLong(askedUUID.getLeastSignificantBits());
|
buffer.putLong(askedUUID.getLeastSignificantBits());
|
||||||
buffer.put(Codes.Device.SPEAKER_DEVICE);
|
buffer.put(AudioServer.SPEAKER_DEVICE);
|
||||||
|
|
||||||
BytesUtils.writeString(buffer, speakerName);
|
BytesUtils.writeString(buffer, speakerName);
|
||||||
|
|
||||||
@ -92,15 +82,10 @@ public class SpeakerServer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void askForStream(int micId) {
|
public void askForStream(int micId) {
|
||||||
|
ByteBuffer buffer = ByteBuffer.allocate(AudioServer.packetMaxSize);
|
||||||
if(listeningTo==micId)
|
|
||||||
return;
|
|
||||||
|
|
||||||
|
|
||||||
ByteBuffer buffer = ByteBuffer.allocate(Codes.packetMaxSize);
|
buffer.put(AudioServer.START_STREAMING);
|
||||||
|
|
||||||
|
|
||||||
buffer.put(Codes.ASK_STREAMING);
|
|
||||||
buffer.putInt(micId);
|
buffer.putInt(micId);
|
||||||
buffer.putInt(speakerId);
|
buffer.putInt(speakerId);
|
||||||
|
|
||||||
@ -112,130 +97,96 @@ public class SpeakerServer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void askStopStreaming() {
|
public void stopStreaming() {
|
||||||
if(listeningTo==-1) {
|
ByteBuffer buffer = ByteBuffer.allocate(AudioServer.packetMaxSize);
|
||||||
System.out.println("J'arêtte d'écouter le vide");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ByteBuffer buffer = ByteBuffer.allocate(Codes.packetMaxSize);
|
|
||||||
|
|
||||||
|
|
||||||
buffer.put(Codes.ASK_STOP_STREAMING);
|
buffer.put(AudioServer.STOP_STREAMING);
|
||||||
buffer.putInt(listeningTo);
|
buffer.putInt(listeningTo);
|
||||||
buffer.putInt(speakerId);
|
buffer.putInt(speakerId);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
serveur.sendData(buffer,masterAddress);
|
serveur.sendData(buffer,masterAddress);
|
||||||
listeningTo=-1;
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void askAudioList() {
|
public void askAudioList() {
|
||||||
ByteBuffer buffer = ByteBuffer.allocate(Codes.packetMaxSize);
|
ByteBuffer buffer = ByteBuffer.allocate(AudioServer.packetMaxSize);
|
||||||
buffer.put(Codes.ASK_AUDIO_LIST);
|
buffer.put(AudioServer.ASK_AUDIO_LIST);
|
||||||
try {
|
try {
|
||||||
serveur.sendData(buffer,masterAddress);
|
serveur.sendData(buffer,masterAddress);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public Map<Integer,String> getAudioList() {
|
||||||
|
return getAudioList(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<Integer,String> getAudioList(boolean invalidate) {
|
||||||
|
isMicListUpToDate = !invalidate && isMicListUpToDate;
|
||||||
|
if(!isMicListUpToDate)askAudioList();
|
||||||
|
while(!isMicListUpToDate) {
|
||||||
|
try {
|
||||||
|
Thread.sleep(1);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
System.out.println("Voici les "+mics);
|
||||||
|
return mics;
|
||||||
|
}
|
||||||
|
|
||||||
public void receiveCommand(ByteBuffer data) {
|
public void receiveCommand(ByteBuffer data) {
|
||||||
byte commande = data.get();
|
byte commande = data.get();
|
||||||
System.out.println("Commande recue : "+commande);
|
System.out.println("Commande recue : "+commande);
|
||||||
switch (commande) {
|
switch (commande) {
|
||||||
|
|
||||||
case Codes.AUDIO_STREAM:
|
case AudioServer.AUDIO_STREAM:
|
||||||
int micId = data.getInt();
|
int micId = data.getInt();
|
||||||
if(micId != listeningTo)break;
|
if(micId != listeningTo)return;
|
||||||
|
data.compact();
|
||||||
byte[] audioData=new byte[data.remaining()];
|
byte[] audioData=new byte[data.remaining()];
|
||||||
data.get(audioData);//XXX Check wether audio data starts at position and not at 0
|
data.get(audioData);//XXX Check wether audio data starts at position and not at 0
|
||||||
speakerLine.write(audioData, 0, audioData.length);
|
speakerLine.write(audioData, 0, packetLength);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Codes.OK_ID:
|
case AudioServer.OK_ID:
|
||||||
UUID uuid = new UUID(data.getLong(), data.getLong());
|
UUID uuid = new UUID(data.getLong(), data.getLong());
|
||||||
byte deviceType = data.get();
|
byte deviceType = data.get();
|
||||||
int deviceId = data.getInt();
|
int deviceId = data.getInt();
|
||||||
|
|
||||||
if(!askedUUID.equals(uuid) || deviceType!=Codes.Device.SPEAKER_DEVICE)
|
if(!askedUUID.equals(uuid) || deviceType!=AudioServer.SPEAKER_DEVICE)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
speakerId = deviceId;
|
speakerId = deviceId;
|
||||||
new Thread(serverAnswered).start();
|
serverAnswered.run();
|
||||||
if(!speakerLine.isOpen())
|
if(speakerLine==null)
|
||||||
try {
|
try {
|
||||||
initializeSpeakerDevice();
|
initializeSpeakerDevice();
|
||||||
} catch (LineUnavailableException e) {
|
} catch (LineUnavailableException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
askAudioList();
|
|
||||||
break;
|
break;
|
||||||
case Codes.GIVE_AUDIO_LIST:
|
case AudioServer.GIVE_AUDIO_LIST:
|
||||||
int micCount = data.getInt();
|
int micCount = data.getInt();
|
||||||
mics = new HashMap<Integer, String>(micCount);
|
mics = new HashMap<Integer, String>(micCount);
|
||||||
for(int i = 0; i<micCount;i++) {
|
for(int i = 0; i<micCount;i++) {
|
||||||
int thisMicId = data.getInt();
|
int thisMicId = data.getInt();
|
||||||
mics.put(thisMicId,BytesUtils.readString(data));
|
mics.put(thisMicId,BytesUtils.readString(data));
|
||||||
}
|
}
|
||||||
System.out.println("Audio list given: "+mics);
|
isMicListUpToDate=true;
|
||||||
micListUpdateListener.forEach(c -> c.accept(mics));
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Codes.DISCONNECTING:
|
|
||||||
byte deviceType2 = data.get();
|
|
||||||
int deviceId2 = data.getInt();
|
|
||||||
if(deviceType2==Codes.Device.MASTER_DEVICE) {
|
|
||||||
System.out.println("Le master s'est déconnécté, on fait de même !");
|
|
||||||
masterAddress=null;
|
|
||||||
this.dispose();
|
|
||||||
for(Runnable toRun : disconnectListener)
|
|
||||||
toRun.run();
|
|
||||||
}else if(deviceType2==Codes.Device.MIC_DEVICE){
|
|
||||||
if(listeningTo==deviceId2) {
|
|
||||||
System.out.println("Le micro que l'on écoutait s'est déconnécté.");
|
|
||||||
listeningTo=-1;
|
|
||||||
for(Runnable toRun : brokenMicListener)
|
|
||||||
toRun.run();
|
|
||||||
}
|
|
||||||
}else {
|
|
||||||
System.out.println("Un appareil de type "+deviceType2+" s'est déconécté, mais je m'en fout ^^");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Codes.STOP_STREAMING:
|
|
||||||
int deviceId3 = data.getInt();
|
|
||||||
if(listeningTo==deviceId3) {
|
|
||||||
System.out.println("Le micro que l'on écoutait arêtte d'émmetre.");
|
|
||||||
listeningTo=-1;
|
|
||||||
for(Runnable toRun : brokenMicListener)
|
|
||||||
toRun.run();
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
System.out.println("Je ne devait pas recevoir cette commade !");
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public void dispose() {
|
public void dispose() {
|
||||||
if(masterAddress!=null) {
|
|
||||||
ByteBuffer decoPacket = ByteBuffer.allocate(Codes.packetMaxSize);
|
|
||||||
decoPacket.put(Codes.DISCONNECTING);
|
|
||||||
decoPacket.put(Codes.Device.SPEAKER_DEVICE);
|
|
||||||
decoPacket.putInt(speakerId);
|
|
||||||
try {
|
|
||||||
serveur.sendData(decoPacket,masterAddress);
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(mics!=null)mics.clear();
|
|
||||||
if(speakerLine!=null) {
|
|
||||||
speakerLine.stop();
|
|
||||||
speakerLine.close();
|
speakerLine.close();
|
||||||
}
|
serveur.dispose();
|
||||||
serveur.close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setServerAnswered(Runnable serverAnswered) {
|
public void setServerAnswered(Runnable serverAnswered) {
|
||||||
@ -243,26 +194,7 @@ public class SpeakerServer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void addDisconnectListener(Runnable listener) {
|
|
||||||
disconnectListener.add(listener);
|
|
||||||
}
|
|
||||||
public void removeDisconnectListener(Runnable listener) {
|
|
||||||
disconnectListener.remove(listener);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addBrokenMicListener(Runnable listener) {
|
|
||||||
brokenMicListener.add(listener);
|
|
||||||
}
|
|
||||||
public void removeBrokenMicListener(Runnable listener) {
|
|
||||||
brokenMicListener.remove(listener);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addMicListUpdateListener(Consumer<Map<Integer, String>> listener) {
|
|
||||||
micListUpdateListener.add(listener);
|
|
||||||
}
|
|
||||||
public void removeMicListUpdateListener(Consumer<Map<Integer, String>> listener) {
|
|
||||||
micListUpdateListener.remove(listener);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,9 +1,15 @@
|
|||||||
package com.bernard.murder.game;
|
package com.bernard.murder.game;
|
||||||
|
|
||||||
import static com.bernard.util.ParseUtils.mappingStringKeys;
|
import static com.bernard.murder.ParseUtils.mappingKeys;
|
||||||
import static com.bernard.util.ParseUtils.parseTimeLength;
|
import static com.bernard.murder.ParseUtils.parseTimeLength;
|
||||||
import static com.bernard.util.ParseUtils.sequenceStream;
|
import static com.bernard.murder.ParseUtils.sequenceStream;
|
||||||
import static com.bernard.util.ParseUtils.watch;
|
|
||||||
|
import static com.bernard.murder.ParseUtils.watch;
|
||||||
|
|
||||||
|
import static com.bernard.murder.YamlUtils.getMapping;
|
||||||
|
import static com.bernard.murder.YamlUtils.isMapping;
|
||||||
|
import static com.bernard.murder.YamlUtils.getSequence;
|
||||||
|
import static com.bernard.murder.YamlUtils.isSequence;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileWriter;
|
import java.io.FileWriter;
|
||||||
@ -26,13 +32,13 @@ import com.amihaiemil.eoyaml.YamlMappingBuilder;
|
|||||||
import com.amihaiemil.eoyaml.YamlNode;
|
import com.amihaiemil.eoyaml.YamlNode;
|
||||||
import com.amihaiemil.eoyaml.YamlPrinter;
|
import com.amihaiemil.eoyaml.YamlPrinter;
|
||||||
import com.amihaiemil.eoyaml.YamlSequence;
|
import com.amihaiemil.eoyaml.YamlSequence;
|
||||||
|
import com.bernard.murder.ParseUtils;
|
||||||
import com.bernard.murder.model.Action;
|
import com.bernard.murder.model.Action;
|
||||||
import com.bernard.murder.model.Objet;
|
import com.bernard.murder.model.Objet;
|
||||||
import com.bernard.murder.model.Partie;
|
import com.bernard.murder.model.Partie;
|
||||||
import com.bernard.murder.model.Personnage;
|
import com.bernard.murder.model.Personnage;
|
||||||
import com.bernard.murder.model.Piece;
|
import com.bernard.murder.model.Piece;
|
||||||
import com.bernard.murder.model.Status;
|
import com.bernard.murder.model.Status;
|
||||||
import com.bernard.util.ParseUtils;
|
|
||||||
|
|
||||||
public class GameCreator {
|
public class GameCreator {
|
||||||
|
|
||||||
@ -42,13 +48,13 @@ public class GameCreator {
|
|||||||
YamlInput input = Yaml.createYamlInput(toread);
|
YamlInput input = Yaml.createYamlInput(toread);
|
||||||
YamlMapping globalMap = input.readYamlMapping();
|
YamlMapping globalMap = input.readYamlMapping();
|
||||||
|
|
||||||
YamlMapping yjoueurs = globalMap.yamlMapping("joueurs");
|
YamlMapping yjoueurs = getMapping(globalMap.value("joueurs"));
|
||||||
|
|
||||||
// Pour pouvoir créer les objets et les espaces personnels
|
// Pour pouvoir créer les objets et les espaces personnels
|
||||||
Set<String> playerNames = mappingStringKeys(yjoueurs).stream().map(n -> n.toString()).collect(Collectors.toSet());
|
Set<String> playerNames = mappingKeys(yjoueurs).stream().map(n -> n.toString()).collect(Collectors.toSet());
|
||||||
|
|
||||||
|
|
||||||
YamlMapping yactions = globalMap.yamlMapping("actions");
|
YamlMapping yactions = getMapping(globalMap.value("actions"));
|
||||||
Set<Action> actions = yactions.keys()
|
Set<Action> actions = yactions.keys()
|
||||||
.stream()
|
.stream()
|
||||||
.map(n -> new Action(n.asScalar().value(), parseTimeLength(yactions.string(n))))
|
.map(n -> new Action(n.asScalar().value(), parseTimeLength(yactions.string(n))))
|
||||||
@ -56,40 +62,35 @@ public class GameCreator {
|
|||||||
Map<String,Set<Action>> persActions = playerNames.stream()
|
Map<String,Set<Action>> persActions = playerNames.stream()
|
||||||
.collect(Collectors.toMap(Function.identity(), s -> actions.stream().map(Action::clone).collect(Collectors.toSet())));
|
.collect(Collectors.toMap(Function.identity(), s -> actions.stream().map(Action::clone).collect(Collectors.toSet())));
|
||||||
|
|
||||||
YamlSequence yinventory = globalMap.yamlSequence("inventaire");
|
YamlSequence yinventory = getSequence(globalMap.value("inventaire"));
|
||||||
|
|
||||||
Set<String> objets = StreamSupport.stream(Spliterators.spliteratorUnknownSize(yinventory.iterator(),Spliterator.ORDERED),false)
|
Set<String> objets = StreamSupport.stream(Spliterators.spliteratorUnknownSize(yinventory.iterator(),Spliterator.ORDERED),false)
|
||||||
.map(n ->n.asScalar().value())
|
.map(n ->n.asScalar().value())
|
||||||
.collect(Collectors.toSet());
|
.collect(Collectors.toSet());
|
||||||
Map<String,Set<Objet>> persObjets =
|
Map<String,Set<Objet>> persObjets = playerNames.stream()
|
||||||
playerNames.stream()
|
.collect(Collectors.toMap(Function.identity(),p -> objets.stream().map(o ->new Objet(String.format(o,p))).collect(Collectors.toSet())));
|
||||||
.collect(Collectors.toMap(
|
|
||||||
Function.identity(),
|
YamlSequence ystatus = getSequence(globalMap.value("status"));
|
||||||
p -> objets.stream()
|
|
||||||
.map(o ->new Objet(String.format(o,p)))
|
|
||||||
.collect(Collectors.toSet())
|
|
||||||
));
|
|
||||||
YamlSequence ystatus = globalMap.yamlSequence("status");
|
|
||||||
Set<Status> status = sequenceStream(ystatus).map(n -> new Status(n.asScalar().value())).collect(Collectors.toSet());
|
Set<Status> status = sequenceStream(ystatus).map(n -> new Status(n.asScalar().value())).collect(Collectors.toSet());
|
||||||
|
|
||||||
YamlMapping yespaces = globalMap.yamlMapping("espaces");
|
YamlMapping yespaces = getMapping(globalMap.value("espaces"));
|
||||||
|
|
||||||
Map<String, Map<Objet, Integer>> objetsDansEspaces = yespaces.keys().stream().collect(Collectors.toMap(
|
Map<String, Map<Objet, Integer>> objetsDansEspaces = yespaces.keys().stream().collect(Collectors.toMap(
|
||||||
n -> n.asScalar().value(),
|
n -> n.asScalar().value(),
|
||||||
n-> parseHiddenObjects(yespaces.yamlSequence(n))
|
n-> parseHiddenObjects(getSequence(yespaces.value(n)))
|
||||||
));
|
));
|
||||||
Set<Piece> espaceObjets = yespaces.keys().stream()
|
Set<Piece> espaceObjets = yespaces.keys().stream()
|
||||||
.map(n -> new Piece(n.asScalar().value(), objetsDansEspaces.get(n.asScalar().value())))
|
.map(n -> new Piece(n.asScalar().value(), objetsDansEspaces.get(n.asScalar().value())))
|
||||||
.collect(Collectors.toSet());
|
.collect(Collectors.toSet());
|
||||||
|
|
||||||
YamlMapping yespacesPersos = globalMap.yamlMapping("espacesPersos");
|
YamlMapping yespacesPersos = getMapping(globalMap.value("espacesPersos"));
|
||||||
|
|
||||||
Map<String,Set<Piece>> persespacesPersos = playerNames.stream().collect(Collectors.toMap(
|
Map<String,Set<Piece>> persespacesPersos = playerNames.stream().collect(Collectors.toMap(
|
||||||
Function.identity(),
|
Function.identity(),
|
||||||
p -> yespacesPersos.keys().stream()
|
p -> yespacesPersos.keys().stream()
|
||||||
.map(e -> new Piece(
|
.map(e -> new Piece(
|
||||||
String.format(e.asScalar().value(), p),
|
String.format(e.asScalar().value(), p),
|
||||||
parseHiddenObjects(yespacesPersos.yamlSequence(e),p)
|
parseHiddenObjects(getSequence(yespacesPersos.value(e)),p)
|
||||||
))
|
))
|
||||||
.collect(Collectors.toSet())
|
.collect(Collectors.toSet())
|
||||||
));
|
));
|
||||||
@ -98,33 +99,32 @@ public class GameCreator {
|
|||||||
for(YamlNode pn : yjoueurs.keys()) {
|
for(YamlNode pn : yjoueurs.keys()) {
|
||||||
String pname = pn.asScalar().value();
|
String pname = pn.asScalar().value();
|
||||||
persActions.get(pname).addAll(
|
persActions.get(pname).addAll(
|
||||||
yjoueurs.yamlMapping(pn).yamlMapping("actions").keys()
|
getMapping(getMapping(yjoueurs.value(pn)).value("actions")).keys()
|
||||||
.stream()
|
.stream()
|
||||||
.map(n -> new Action(n.asScalar().value(), parseTimeLength(yjoueurs.yamlMapping(pn).yamlMapping("actions").string(n))))
|
.map(n -> new Action(n.asScalar().value(), parseTimeLength(getMapping(getMapping(yjoueurs.value(pn)).value("actions")).string(n))))
|
||||||
.collect(Collectors.toSet())
|
.collect(Collectors.toSet())
|
||||||
);
|
);
|
||||||
persObjets.get(pname).addAll(
|
persObjets.get(pname).addAll(
|
||||||
StreamSupport.stream(Spliterators.spliteratorUnknownSize(yjoueurs.yamlMapping(pn).yamlSequence("inventaire").iterator(),Spliterator.ORDERED),false)
|
StreamSupport.stream(Spliterators.spliteratorUnknownSize(getSequence(getMapping(yjoueurs.value(pn)).value("inventaire")).iterator(),Spliterator.ORDERED),false)
|
||||||
.map(n ->n.asScalar().value())
|
.map(n ->n.asScalar().value())
|
||||||
.map(o ->new Objet(o))
|
.map(o ->new Objet(o))
|
||||||
.collect(Collectors.toSet())
|
.collect(Collectors.toSet())
|
||||||
);
|
);
|
||||||
|
if(isMapping(getMapping(yjoueurs.value(pn)).value("espacePerso")))
|
||||||
if(yjoueurs.yamlMapping(pn).value("espacePerso").type()==Node.MAPPING)
|
|
||||||
// Plusieurs espaces
|
// Plusieurs espaces
|
||||||
yjoueurs.yamlMapping(pn).yamlMapping("espacePerso").keys().forEach(n ->
|
getMapping(getMapping(yjoueurs.value(pn)).value("espacePerso")).keys().forEach(n ->
|
||||||
persespacesPersos.get(pname)
|
persespacesPersos.get(pname)
|
||||||
.stream()
|
.stream()
|
||||||
.filter(p -> p.getNom().contentEquals(n.asScalar().value()))
|
.filter(p -> p.getNom().contentEquals(n.asScalar().value()))
|
||||||
.findAny()
|
.findAny()
|
||||||
.orElseGet(() -> new Piece(n.asScalar().value()))
|
.orElseGet(() -> new Piece(n.asScalar().value()))
|
||||||
.insertObjects(parseHiddenObjects(yjoueurs.yamlMapping(pn).yamlMapping("espacePerso").yamlSequence(n)))
|
.insertObjects(parseHiddenObjects(getSequence(getMapping(getMapping(yjoueurs.value(pn)).value("espacePerso")).value(n))))
|
||||||
|
|
||||||
);
|
);
|
||||||
else
|
else
|
||||||
((persespacesPersos.get(pname).isEmpty())?
|
((persespacesPersos.get(pname).isEmpty())?
|
||||||
Stream.of(new Piece(String.format("Espace de %s",pname))):persespacesPersos.get(pname).stream())
|
Stream.of(new Piece(String.format("Espace de %s",pname))):persespacesPersos.get(pname).stream())
|
||||||
.forEach(p -> p.insertObjects(parseHiddenObjects(yjoueurs.yamlMapping(pn).yamlSequence("espacePerso"))));
|
.forEach(p -> p.insertObjects(parseHiddenObjects(getSequence(getMapping(yjoueurs.value(pn)).value("espacePerso")))));
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -137,8 +137,8 @@ public class GameCreator {
|
|||||||
persActions.get(p),
|
persActions.get(p),
|
||||||
status.stream().filter(st -> sequenceStream(ystatus)
|
status.stream().filter(st -> sequenceStream(ystatus)
|
||||||
.filter(n -> n instanceof YamlMapping)
|
.filter(n -> n instanceof YamlMapping)
|
||||||
.filter(n -> n.asMapping().string(st.getName())!=null)
|
.filter(n -> getMapping(n).string(st.getName())!=null)
|
||||||
.filter(n -> (n.asMapping().yamlMapping(st.getName())).string("onStart").contentEquals("true"))
|
.filter(n -> getMapping(getMapping(n).value(st.getName())).string("onStart").contentEquals("true"))
|
||||||
.findAny().isPresent())
|
.findAny().isPresent())
|
||||||
.collect(Collectors.toSet()),
|
.collect(Collectors.toSet()),
|
||||||
persespacesPersos.get(p)
|
persespacesPersos.get(p)
|
||||||
@ -203,50 +203,50 @@ public class GameCreator {
|
|||||||
YamlInput input = Yaml.createYamlInput(f);
|
YamlInput input = Yaml.createYamlInput(f);
|
||||||
YamlMapping globalMap = input.readYamlMapping();
|
YamlMapping globalMap = input.readYamlMapping();
|
||||||
|
|
||||||
YamlSequence ystatus = globalMap.yamlSequence("status");
|
YamlSequence ystatus = getSequence(globalMap.value("status"));
|
||||||
Set<Status> status = sequenceStream(ystatus).map(n -> new Status(n.asScalar().value())).collect(Collectors.toSet());
|
Set<Status> status = sequenceStream(ystatus).map(n -> new Status(n.asScalar().value())).collect(Collectors.toSet());
|
||||||
|
|
||||||
|
|
||||||
YamlMapping yespaces = globalMap.yamlMapping("pieces");
|
YamlMapping yespaces = getMapping(globalMap.value("pieces"));
|
||||||
Map<String, Map<Objet, Integer>> objetsDansEspaces = yespaces.keys().stream().collect(Collectors.toMap(
|
Map<String, Map<Objet, Integer>> objetsDansEspaces = yespaces.keys().stream().collect(Collectors.toMap(
|
||||||
n -> watch(watch(n).asScalar().value()),
|
n -> watch(watch(n).asScalar().value()),
|
||||||
n-> parseHiddenObjects(yespaces.yamlSequence(n))
|
n-> parseHiddenObjects(getSequence(yespaces.value(n)))
|
||||||
));
|
));
|
||||||
Set<Piece> espaceObjets = yespaces.keys().stream()
|
Set<Piece> espaceObjets = yespaces.keys().stream()
|
||||||
.map(n -> new Piece(n.asScalar().value(), objetsDansEspaces.get(n.asScalar().value())))
|
.map(n -> new Piece(n.asScalar().value(), objetsDansEspaces.get(n.asScalar().value())))
|
||||||
.collect(Collectors.toSet());
|
.collect(Collectors.toSet());
|
||||||
|
|
||||||
|
|
||||||
YamlMapping yjoueurs = globalMap.yamlMapping("personnages");
|
YamlMapping yjoueurs = getMapping(globalMap.value("personnages"));
|
||||||
|
|
||||||
Set<Personnage> personnages = new HashSet<Personnage>();
|
Set<Personnage> personnages = new HashSet<Personnage>();
|
||||||
for(YamlNode pn : yjoueurs.keys()) {
|
for(YamlNode pn : yjoueurs.keys()) {
|
||||||
String pname = pn.asScalar().value();
|
String pname = pn.asScalar().value();
|
||||||
|
|
||||||
Set<Action> actions = yjoueurs.yamlMapping(pn).yamlMapping("actions").keys()
|
Set<Action> actions = getMapping(getMapping(yjoueurs.value(pn)).value("actions")).keys()
|
||||||
.stream()
|
.stream()
|
||||||
.map(n -> new Action(n.asScalar().value(), Long.parseLong(yjoueurs.yamlMapping(pn).yamlMapping("actions").yamlMapping(n).string("basetime")),
|
.map(n -> new Action(n.asScalar().value(), Long.parseLong(getMapping(getMapping(getMapping(yjoueurs.value(pn)).value("actions")).value(n)).string("basetime")),
|
||||||
Long.parseLong(yjoueurs.yamlMapping(pn).yamlMapping("actions").yamlMapping(n).string("triggerTime"))))
|
Long.parseLong(getMapping(getMapping(getMapping(yjoueurs.value(pn)).value("actions")).value(n)).string("triggerTime"))))
|
||||||
.collect(Collectors.toSet());
|
.collect(Collectors.toSet());
|
||||||
|
|
||||||
Set<Objet> inventaire =
|
Set<Objet> inventaire =
|
||||||
StreamSupport.stream(Spliterators.spliteratorUnknownSize(yjoueurs.yamlMapping(pn).yamlSequence("inventaire").iterator(),Spliterator.ORDERED),false)
|
StreamSupport.stream(Spliterators.spliteratorUnknownSize(getSequence(getMapping(yjoueurs.value(pn)).value("inventaire")).iterator(),Spliterator.ORDERED),false)
|
||||||
.map(n ->n.asScalar().value())
|
.map(n ->n.asScalar().value())
|
||||||
.map(o ->new Objet(o))
|
.map(o ->new Objet(o))
|
||||||
.collect(Collectors.toSet());
|
.collect(Collectors.toSet());
|
||||||
|
|
||||||
Set<Piece> espacesPerso = yjoueurs.yamlMapping(pn).yamlMapping("espacePerso").keys().stream().map(n ->
|
Set<Piece> espacesPerso = getMapping(getMapping(yjoueurs.value(pn)).value("espacePerso")).keys().stream().map(n ->
|
||||||
new Piece(n.asScalar().value(), parseHiddenObjects(yjoueurs.yamlMapping(pn).yamlMapping("espacePerso").yamlSequence(n)))).collect(Collectors.toSet());
|
new Piece(n.asScalar().value(), parseHiddenObjects(getSequence(getMapping(getMapping(yjoueurs.value(pn)).value("espacePerso")).value(n))))).collect(Collectors.toSet());
|
||||||
|
|
||||||
Set<Status> persoStatus = status.stream().filter(
|
Set<Status> persoStatus = status.stream().filter(
|
||||||
s -> (yjoueurs.yamlMapping(pn).value("status").type()!=Node.SEQUENCE)?false:yjoueurs.yamlMapping(pn).yamlSequence("status").values().stream().anyMatch(n -> n.asScalar().value().equals(s.getName()))
|
s -> !isSequence(getMapping(yjoueurs.value(pn)).value("status"))?false:getSequence(getMapping(yjoueurs.value(pn)).value("status")).values().stream().anyMatch(n -> n.asScalar().value().equals(s.getName()))
|
||||||
).collect(Collectors.toSet());
|
).collect(Collectors.toSet());
|
||||||
|
|
||||||
|
|
||||||
personnages.add(new Personnage(pname, inventaire, actions, persoStatus, espacesPerso));
|
personnages.add(new Personnage(pname, inventaire, actions, persoStatus, espacesPerso));
|
||||||
}
|
}
|
||||||
|
|
||||||
YamlMapping minelsMap = globalMap.yamlMapping("minels");
|
YamlMapping minelsMap = getMapping(globalMap.value("minels"));
|
||||||
|
|
||||||
return new QuicksavedPartie(new Partie(personnages, status, espaceObjets),minelsMap);
|
return new QuicksavedPartie(new Partie(personnages, status, espaceObjets),minelsMap);
|
||||||
|
|
||||||
|
|||||||
@ -17,7 +17,6 @@ import javax.swing.Timer;
|
|||||||
|
|
||||||
import com.amihaiemil.eoyaml.Yaml;
|
import com.amihaiemil.eoyaml.Yaml;
|
||||||
import com.amihaiemil.eoyaml.YamlMapping;
|
import com.amihaiemil.eoyaml.YamlMapping;
|
||||||
import com.bernard.murder.model.Action;
|
|
||||||
import com.bernard.murder.model.Inventaire;
|
import com.bernard.murder.model.Inventaire;
|
||||||
import com.bernard.murder.model.Objet;
|
import com.bernard.murder.model.Objet;
|
||||||
import com.bernard.murder.model.Partie;
|
import com.bernard.murder.model.Partie;
|
||||||
@ -27,7 +26,6 @@ public class GameManager {
|
|||||||
|
|
||||||
Partie partie;
|
Partie partie;
|
||||||
Map<Inventaire,Set<Runnable>> inventoryUpdateListeners;
|
Map<Inventaire,Set<Runnable>> inventoryUpdateListeners;
|
||||||
Map<Personnage,Set<Runnable>> actionsUpdateListeners;
|
|
||||||
|
|
||||||
long startTime;
|
long startTime;
|
||||||
|
|
||||||
@ -38,7 +36,6 @@ public class GameManager {
|
|||||||
public GameManager(Partie partie) {
|
public GameManager(Partie partie) {
|
||||||
this.partie = partie;
|
this.partie = partie;
|
||||||
this.inventoryUpdateListeners = new HashMap<Inventaire, Set<Runnable>>();
|
this.inventoryUpdateListeners = new HashMap<Inventaire, Set<Runnable>>();
|
||||||
this.actionsUpdateListeners = new HashMap<Personnage, Set<Runnable>>();
|
|
||||||
this.minelsQuicksaver = () -> Yaml.createYamlMappingBuilder().build();
|
this.minelsQuicksaver = () -> Yaml.createYamlMappingBuilder().build();
|
||||||
startTime = System.currentTimeMillis();
|
startTime = System.currentTimeMillis();
|
||||||
|
|
||||||
@ -60,14 +57,6 @@ public class GameManager {
|
|||||||
for(Runnable r : inventoryUpdateListeners.get(inv))
|
for(Runnable r : inventoryUpdateListeners.get(inv))
|
||||||
r.run();
|
r.run();
|
||||||
}
|
}
|
||||||
public void actionsUpdate(Action act) {
|
|
||||||
actionsUpdate(partie.personnagesStream().filter(p->p.getActions().contains(act)).findAny().get());
|
|
||||||
}
|
|
||||||
public void actionsUpdate(Personnage inv) {
|
|
||||||
if(!actionsUpdateListeners.containsKey(inv))return;
|
|
||||||
for(Runnable r : actionsUpdateListeners.get(inv))
|
|
||||||
r.run();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void dumpCurrentState() {
|
public void dumpCurrentState() {
|
||||||
System.out.println(partie);
|
System.out.println(partie);
|
||||||
@ -78,24 +67,19 @@ public class GameManager {
|
|||||||
inventoryUpdateListeners.put(inv, new HashSet<Runnable>());
|
inventoryUpdateListeners.put(inv, new HashSet<Runnable>());
|
||||||
inventoryUpdateListeners.get(inv).add(runnable);
|
inventoryUpdateListeners.get(inv).add(runnable);
|
||||||
}
|
}
|
||||||
public void addActionsUpdateListener(Personnage perso, Runnable runnable) {
|
|
||||||
if(!actionsUpdateListeners.containsKey(perso))
|
|
||||||
actionsUpdateListeners.put(perso, new HashSet<Runnable>());
|
|
||||||
actionsUpdateListeners.get(perso).add(runnable);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void quickSave() {
|
public void quickSave() {
|
||||||
|
System.out.println("Quicksaving");
|
||||||
File toSave = new File(quickSaveFilename());
|
File toSave = new File(quickSaveFilename());
|
||||||
File tempOldSave = new File(quickSaveFilename()+".tmp");
|
File tempOldSave = new File(quickSaveFilename()+".tmp");
|
||||||
if(toSave.exists())toSave.renameTo(tempOldSave);
|
if(toSave.exists())toSave.renameTo(tempOldSave);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
GameCreator.quickSave(toSave, partie,minelsQuicksaver.get());
|
GameCreator.quickSave(toSave, partie,minelsQuicksaver.get());
|
||||||
|
System.out.println("Quicksaved");
|
||||||
if(tempOldSave.exists())tempOldSave.delete();
|
if(tempOldSave.exists())tempOldSave.delete();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
System.err.println("La sauvegarde rapide n'a pas fonctionné. Elle est donc désactivée.");
|
|
||||||
quickSaver.stop();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -104,12 +88,6 @@ public class GameManager {
|
|||||||
return "murder-"+DateTimeFormatter.ofPattern("uu-MM-dd_HH'h'mm").withZone(ZoneId.systemDefault()).withLocale(Locale.getDefault()).format(Instant.ofEpochMilli(startTime))+".bernard.quickmurder";
|
return "murder-"+DateTimeFormatter.ofPattern("uu-MM-dd_HH'h'mm").withZone(ZoneId.systemDefault()).withLocale(Locale.getDefault()).format(Instant.ofEpochMilli(startTime))+".bernard.quickmurder";
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeQuickSaves() {
|
|
||||||
for(File f : (new File(".")).listFiles((f,n) -> n.startsWith("murder-") && n.endsWith(".bernard.quickmurder"))) {
|
|
||||||
f.delete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set<Inventaire> getEveryInventaire() {
|
public Set<Inventaire> getEveryInventaire() {
|
||||||
Set<Inventaire> inventaires = new HashSet<Inventaire>();
|
Set<Inventaire> inventaires = new HashSet<Inventaire>();
|
||||||
inventaires.addAll(partie.pieces());
|
inventaires.addAll(partie.pieces());
|
||||||
@ -130,10 +108,6 @@ public class GameManager {
|
|||||||
return partie.personnagesStream().filter(p -> key.equalsIgnoreCase(p.getNom())).findAny().orElse(null);
|
return partie.personnagesStream().filter(p -> key.equalsIgnoreCase(p.getNom())).findAny().orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Personnage getPersoHavingAction(Action act) {
|
|
||||||
return partie.personnagesStream().filter(p -> p.getActions().contains(act)).findAny().orElse(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void bindMinelQuicksaver(Supplier<YamlMapping> minelsQuicksaver) {
|
public void bindMinelQuicksaver(Supplier<YamlMapping> minelsQuicksaver) {
|
||||||
this.minelsQuicksaver = minelsQuicksaver;
|
this.minelsQuicksaver = minelsQuicksaver;
|
||||||
}
|
}
|
||||||
@ -144,43 +118,9 @@ public class GameManager {
|
|||||||
inventaires.addAll(partie.personnages());
|
inventaires.addAll(partie.personnages());
|
||||||
partie.personnagesStream().forEach(p -> inventaires.addAll(p.espacePersos()));
|
partie.personnagesStream().forEach(p -> inventaires.addAll(p.espacePersos()));
|
||||||
return inventaires.stream().filter(i -> name.equalsIgnoreCase(i.getInventoryName())).findAny().orElseGet(()->{
|
return inventaires.stream().filter(i -> name.equalsIgnoreCase(i.getInventoryName())).findAny().orElseGet(()->{
|
||||||
System.err.println("JE n'ai pas trouvé l'inventaire "+name+" dans la liste "+inventaires.stream().map(Inventaire::getInventoryName).collect(Collectors.joining(",")));
|
System.out.println("JE n'ai pas trouvé l'inventaire "+name+" dans la liste "+inventaires.stream().map(Inventaire::getInventoryName).collect(Collectors.joining(",")));
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void createObjet(String newName, Inventaire inv) {
|
|
||||||
Objet o = new Objet(newName);
|
|
||||||
System.out.println("Création de l'objet "+o+" dans "+inv);
|
|
||||||
inv.addObjet(o);
|
|
||||||
inventoryUpdate(inv);
|
|
||||||
}
|
|
||||||
public void deleteObjet(Objet o, Inventaire inv) {
|
|
||||||
System.out.println("Destruction de l'objet "+o+" dans "+inv);
|
|
||||||
inv.removeObjet(o);
|
|
||||||
inventoryUpdate(inv);
|
|
||||||
}
|
|
||||||
public void renameObjet(Objet o, String newName, Inventaire inv) {
|
|
||||||
System.out.println("Renommage de l'objet "+o+" en "+newName+" dans "+inv);
|
|
||||||
Objet newObjet = new Objet(newName);
|
|
||||||
inv.removeObjet(o);
|
|
||||||
inv.addObjet(newObjet);
|
|
||||||
inventoryUpdate(inv);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void launchAction(Action a) {
|
|
||||||
a.setTriggertime(System.currentTimeMillis());
|
|
||||||
actionsUpdate(a);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void resetAction(Action a) {
|
|
||||||
a.setTriggertime(0);
|
|
||||||
actionsUpdate(a);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Partie partie() {
|
|
||||||
return partie;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,356 +0,0 @@
|
|||||||
package com.bernard.murder.game;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.SocketAddress;
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Base64;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.concurrent.ThreadLocalRandom;
|
|
||||||
|
|
||||||
import com.bernard.murder.audio.AudioServer;
|
|
||||||
import com.bernard.murder.audio.Codes;
|
|
||||||
import com.bernard.murder.model.Action;
|
|
||||||
import com.bernard.murder.model.Inventaire;
|
|
||||||
import com.bernard.murder.model.Objet;
|
|
||||||
import com.bernard.murder.model.Personnage;
|
|
||||||
import com.bernard.murder.model.messages.Message;
|
|
||||||
import com.bernard.murder.model.messages.Thread;
|
|
||||||
import com.bernard.util.BytesUtils;
|
|
||||||
|
|
||||||
public class GameNetworkInterface {
|
|
||||||
|
|
||||||
public GameManager theManager;
|
|
||||||
AudioServer theServer;
|
|
||||||
|
|
||||||
|
|
||||||
Map<String, String> joueursTokens; // <token, joueur name>
|
|
||||||
Map<String, String> opTokens; // <token, op name>
|
|
||||||
|
|
||||||
Map<String, String> passwords; // <Nom du joueur/op, Mdp>
|
|
||||||
|
|
||||||
Map<String,List<Thread>> messages; // <Nom du joueur, tous les threads>
|
|
||||||
Map<String, Set<SocketAddress>> messageListeners; // <Nom du joueur/op, ensemble des adresses à notifier>
|
|
||||||
|
|
||||||
Set<String> opNames;
|
|
||||||
|
|
||||||
long globalThreadUid = 0L;
|
|
||||||
|
|
||||||
public GameNetworkInterface(GameManager theManager, AudioServer theServer) {
|
|
||||||
this.theManager = theManager;
|
|
||||||
this.theServer = theServer;
|
|
||||||
|
|
||||||
joueursTokens = new HashMap<>();
|
|
||||||
opTokens = new HashMap<>();
|
|
||||||
passwords = new HashMap<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public synchronized void receiveCommand(ByteBuffer cmd,SocketAddress senderAddress) {
|
|
||||||
byte commandePartie = cmd.get();
|
|
||||||
System.out.println("Sous-commande: "+commandePartie);
|
|
||||||
|
|
||||||
String token;
|
|
||||||
switch(commandePartie) {
|
|
||||||
case Codes.Partie.ASK_OP_TOKEN:
|
|
||||||
case Codes.Partie.ASK_JOUEUR_TOKEN:
|
|
||||||
String name = BytesUtils.readString(cmd);
|
|
||||||
String mdp = BytesUtils.readString(cmd);
|
|
||||||
if(!passwords.get(name).equals(mdp)) {
|
|
||||||
// Pas autorisé !!!
|
|
||||||
authError(senderAddress, null);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
byte[] tokenBytes = new byte[72];
|
|
||||||
ThreadLocalRandom.current().nextBytes(tokenBytes);
|
|
||||||
String newToken = Base64.getUrlEncoder().encodeToString(tokenBytes);
|
|
||||||
if(commandePartie == Codes.Partie.ASK_OP_TOKEN) {
|
|
||||||
opTokens.put(newToken, name);
|
|
||||||
opNames.add(name);
|
|
||||||
}
|
|
||||||
if(commandePartie == Codes.Partie.ASK_JOUEUR_TOKEN)
|
|
||||||
joueursTokens.put(newToken, name);
|
|
||||||
System.out.println("Ajout d'un joli token !"+opTokens+";"+joueursTokens);
|
|
||||||
|
|
||||||
//XXX: On enregistre aussi la jolie adresse pour recevoir les messages, c'est cencé bouger
|
|
||||||
messageListeners.putIfAbsent(name, new HashSet<>());
|
|
||||||
messageListeners.get(name).add(senderAddress);
|
|
||||||
|
|
||||||
ByteBuffer outToken = ByteBuffer.allocate(Codes.packetMaxSize);
|
|
||||||
outToken.put(Codes.ACCES_PARTIE);
|
|
||||||
outToken.put(Codes.Partie.GIVING_TOKEN);
|
|
||||||
BytesUtils.writeString(outToken, newToken);
|
|
||||||
try {
|
|
||||||
theServer.serveur.sendData(outToken, senderAddress);
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Codes.Partie.ASK_PLAYER_LIST:
|
|
||||||
//Pas besoin du token pour cette requête
|
|
||||||
ByteBuffer outList = ByteBuffer.allocate(Codes.packetMaxSize);
|
|
||||||
outList.put(Codes.ACCES_PARTIE);
|
|
||||||
outList.put(Codes.Partie.GIVE_PLAYER_LIST);
|
|
||||||
Set<Personnage> persos = theManager.partie.personnages();
|
|
||||||
outList.putInt(persos.size());
|
|
||||||
for(Personnage perso:persos)
|
|
||||||
BytesUtils.writeString(outList, perso.getNom());
|
|
||||||
try {
|
|
||||||
theServer.serveur.sendData(outList, senderAddress);
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Codes.Partie.ASK_INVENTORY:
|
|
||||||
case Codes.Partie.ASK_INVENTORY_WATCH:
|
|
||||||
|
|
||||||
token = BytesUtils.readString(cmd);
|
|
||||||
String invName = BytesUtils.readString(cmd);
|
|
||||||
if(!opTokens.containsKey(token)) {
|
|
||||||
// Alors on teste le joueur.
|
|
||||||
String toktoktoken = token;
|
|
||||||
Personnage perso = theManager.partie.personnagesStream()
|
|
||||||
.filter(p -> p.getNom().equals(joueursTokens.get(toktoktoken)))
|
|
||||||
.findAny().orElse(null);
|
|
||||||
if(!(perso!=null && perso.getInventoryName().equals(invName))) {
|
|
||||||
authError(senderAddress, token);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Autorisééééé
|
|
||||||
sendInventoryContent(senderAddress,invName);
|
|
||||||
if(commandePartie==Codes.Partie.ASK_INVENTORY_WATCH) {
|
|
||||||
theManager.addInventoryUpdateListener(theManager.getInventoryByName(invName), () -> sendInventoryContent(senderAddress,invName));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Codes.Partie.ASK_ACTIONS:
|
|
||||||
case Codes.Partie.ASK_ACTIONS_WATCH:
|
|
||||||
|
|
||||||
token = BytesUtils.readString(cmd);
|
|
||||||
String persoName = BytesUtils.readString(cmd);
|
|
||||||
if(!opTokens.containsKey(token)) {
|
|
||||||
// Alors on teste le joueur.
|
|
||||||
String toktoken = token;
|
|
||||||
Personnage perso = theManager.partie.personnagesStream()
|
|
||||||
.filter(p -> p.getNom().equals(joueursTokens.get(toktoken)))
|
|
||||||
.findAny().orElse(null);
|
|
||||||
if(!(perso!=null && perso.getNom().equals(persoName))) {
|
|
||||||
authError(senderAddress, token);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Autorisééééé
|
|
||||||
sendActionsStatus(senderAddress,persoName);
|
|
||||||
if(commandePartie==Codes.Partie.ASK_INVENTORY_WATCH) {
|
|
||||||
theManager.addActionsUpdateListener(theManager.getPersoByName(persoName), () -> sendActionsStatus(senderAddress,persoName));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Codes.Partie.ASK_NEW_THREAD:
|
|
||||||
token = BytesUtils.readString(cmd);
|
|
||||||
UUID requestId = new UUID(cmd.getLong(), cmd.getLong());
|
|
||||||
long startTimestamp = cmd.getLong();
|
|
||||||
|
|
||||||
if(!joueursTokens.containsKey(token)) {
|
|
||||||
// Mé t ki en fét ?
|
|
||||||
authError(senderAddress, token);
|
|
||||||
return;
|
|
||||||
}else
|
|
||||||
persoName = joueursTokens.get(token);
|
|
||||||
|
|
||||||
long newUid = globalThreadUid++;
|
|
||||||
Thread t = new Thread(persoName, startTimestamp, newUid);
|
|
||||||
messages.putIfAbsent(persoName, new ArrayList<>());
|
|
||||||
messages.get(persoName).add(t);
|
|
||||||
|
|
||||||
ByteBuffer outThr = ByteBuffer.allocate(Codes.packetMaxSize);
|
|
||||||
outThr.put(Codes.ACCES_PARTIE);
|
|
||||||
outThr.put(Codes.Partie.CREATED_NEW_THREAD);
|
|
||||||
outThr.putLong(requestId.getMostSignificantBits());
|
|
||||||
outThr.putLong(requestId.getLeastSignificantBits());
|
|
||||||
BytesUtils.writeString(outThr,persoName);
|
|
||||||
outThr.putLong(newUid);
|
|
||||||
outThr.putLong(startTimestamp);
|
|
||||||
|
|
||||||
Set<SocketAddress> dests = new HashSet<>();
|
|
||||||
dests.addAll(messageListeners.getOrDefault(persoName,Set.of())); // Tous les comptes du joueur
|
|
||||||
dests.add(senderAddress); // Celui qui a envoyé
|
|
||||||
dests.addAll(opAddresses()); // Et tous les opés
|
|
||||||
for(SocketAddress dest : dests){
|
|
||||||
try {
|
|
||||||
theServer.serveur.sendData(outThr, dest);
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Codes.Partie.CLOSE_NEW_THREAD:
|
|
||||||
token = BytesUtils.readString(cmd);
|
|
||||||
long uidToClose = cmd.getLong();
|
|
||||||
long closeTimestamp = cmd.getLong();
|
|
||||||
|
|
||||||
if(!joueursTokens.containsKey(token) && !opTokens.containsKey(token)) {
|
|
||||||
// Mé t ki en fét ?
|
|
||||||
authError(senderAddress, token);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Thread ttc = threadFromUid(uidToClose);
|
|
||||||
persoName = ttc.joueur;
|
|
||||||
ttc.closeTime = closeTimestamp;
|
|
||||||
|
|
||||||
ByteBuffer outThrC = ByteBuffer.allocate(Codes.packetMaxSize);
|
|
||||||
outThrC.put(Codes.ACCES_PARTIE);
|
|
||||||
outThrC.put(Codes.Partie.CLOSED_THREAD);
|
|
||||||
outThrC.putLong(uidToClose);
|
|
||||||
outThrC.putLong(closeTimestamp);
|
|
||||||
Set<SocketAddress> destsC = new HashSet<>();
|
|
||||||
destsC.addAll(messageListeners.getOrDefault(persoName,Set.of())); // Tous les comptes du joueur
|
|
||||||
destsC.add(senderAddress); // Celui qui a envoyé
|
|
||||||
destsC.addAll(opAddresses()); // Et tous les opés
|
|
||||||
for(SocketAddress dest : destsC){
|
|
||||||
try {
|
|
||||||
theServer.serveur.sendData(outThrC, dest);
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Codes.Partie.SEND_MESSAGE:
|
|
||||||
token = BytesUtils.readString(cmd);
|
|
||||||
long sendTimestamp = cmd.getLong();
|
|
||||||
long threadUid = cmd.getLong();
|
|
||||||
String emmeteur = BytesUtils.readString(cmd);
|
|
||||||
String message = BytesUtils.readString(cmd);
|
|
||||||
|
|
||||||
|
|
||||||
if(!(joueursTokens.containsKey(token) && joueursTokens.get(token).equals(emmeteur)) &&
|
|
||||||
!(opTokens.containsKey(token) && opTokens.get(token).equals(emmeteur))) {
|
|
||||||
// Mé t ki en fét ?
|
|
||||||
authError(senderAddress, token);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(threadUid<0) {
|
|
||||||
System.err.println("Je ne sais pas encore traiter les messages hors thread, revenez plus tard");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Thread tt = threadFromUid(threadUid);
|
|
||||||
Message mess = new Message(emmeteur, message, sendTimestamp);
|
|
||||||
int newPos = tt.messages.size();
|
|
||||||
tt.messages.add(mess);
|
|
||||||
|
|
||||||
ByteBuffer outMess = ByteBuffer.allocate(Codes.packetMaxSize);
|
|
||||||
outMess.put(Codes.ACCES_PARTIE);
|
|
||||||
outMess.put(Codes.Partie.NEW_MESSAGE);
|
|
||||||
outMess.putLong(sendTimestamp);
|
|
||||||
outMess.putLong(threadUid);
|
|
||||||
outMess.putInt(newPos);
|
|
||||||
BytesUtils.writeString(outMess,emmeteur);
|
|
||||||
BytesUtils.writeString(outMess,message);
|
|
||||||
|
|
||||||
Set<SocketAddress> destsM = new HashSet<>();
|
|
||||||
destsM.addAll(messageListeners.getOrDefault(tt.joueur,Set.of())); // Tous les comptes du joueur
|
|
||||||
destsM.add(senderAddress); // Celui qui a envoyé
|
|
||||||
destsM.addAll(opAddresses()); // Et tous les opés
|
|
||||||
for(SocketAddress dest : destsM){
|
|
||||||
try {
|
|
||||||
theServer.serveur.sendData(outMess, dest);
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void sendInventoryContent(SocketAddress destinataire, String inventoryName) {
|
|
||||||
Inventaire inv = theManager.getInventoryByName(inventoryName);
|
|
||||||
ByteBuffer outInv = ByteBuffer.allocate(Codes.packetMaxSize);
|
|
||||||
outInv.put(Codes.ACCES_PARTIE);
|
|
||||||
outInv.put(Codes.Partie.INVENTORY_CONTENT);
|
|
||||||
Set<Objet> objs = inv.getObjects();
|
|
||||||
outInv.putInt(objs.size());
|
|
||||||
for(Objet obj:objs)
|
|
||||||
BytesUtils.writeString(outInv, obj.getNom());
|
|
||||||
try {
|
|
||||||
theServer.serveur.sendData(outInv, destinataire);
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void sendActionsStatus(SocketAddress destinataire, String persoName) {
|
|
||||||
System.out.println("Sending actions of "+persoName+ " to "+destinataire);
|
|
||||||
Personnage perso = theManager.getPersoByName(persoName);
|
|
||||||
ByteBuffer outPerso = ByteBuffer.allocate(Codes.packetMaxSize);
|
|
||||||
outPerso.put(Codes.ACCES_PARTIE);
|
|
||||||
outPerso.put(Codes.Partie.ACTIONS_STATUS);
|
|
||||||
BytesUtils.writeString(outPerso, persoName);
|
|
||||||
Set<Action> actions = perso.getActions();
|
|
||||||
outPerso.putInt(actions.size());
|
|
||||||
for(Action act:actions) {
|
|
||||||
BytesUtils.writeString(outPerso, act.getName());
|
|
||||||
outPerso.putLong(act.getBasetime());
|
|
||||||
outPerso.putLong(act.getTriggertime());
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
theServer.serveur.sendData(outPerso, destinataire);
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void authError(SocketAddress responce, String token) {
|
|
||||||
System.out.println("Refus du token "+token);
|
|
||||||
ByteBuffer out = ByteBuffer.allocate(Codes.packetMaxSize);
|
|
||||||
out.put(Codes.ACCES_PARTIE);
|
|
||||||
out.put(Codes.Partie.AUTH_ERROR);
|
|
||||||
if(token!=null)
|
|
||||||
BytesUtils.writeString(out, token);
|
|
||||||
else
|
|
||||||
BytesUtils.writeString(out, "");
|
|
||||||
try {
|
|
||||||
theServer.serveur.sendData(out, responce);
|
|
||||||
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set<SocketAddress> opAddresses(){
|
|
||||||
return opNames.stream()
|
|
||||||
.map(messageListeners::get)
|
|
||||||
.reduce(new HashSet<>(), (a,b) -> {a.addAll(b);return a;});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public void addPass(String nom, String pass) {
|
|
||||||
passwords.put(nom, pass);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Thread threadFromUid(long theUid) {
|
|
||||||
return messages.values().stream()
|
|
||||||
.map(l -> l.stream().filter(t -> t.uid==theUid).findAny())
|
|
||||||
.filter(Optional::isPresent)
|
|
||||||
.findAny()
|
|
||||||
.get()
|
|
||||||
.get()// Vérifié
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -40,6 +40,10 @@ public class Action implements Cloneable{
|
|||||||
return System.currentTimeMillis()-triggertime-basetime>0;
|
return System.currentTimeMillis()-triggertime-basetime>0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void launch() {
|
||||||
|
triggertime=System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
|
||||||
public boolean hasFinished() {
|
public boolean hasFinished() {
|
||||||
return triggertime + basetime - System.currentTimeMillis()<0;
|
return triggertime + basetime - System.currentTimeMillis()<0;
|
||||||
}
|
}
|
||||||
@ -60,10 +64,6 @@ public class Action implements Cloneable{
|
|||||||
return triggertime;
|
return triggertime;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setTriggertime(long triggertime) {
|
|
||||||
this.triggertime = triggertime;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -61,7 +61,9 @@ public class Personnage implements Inventaire {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removeObjet(Objet o) {
|
public void removeObjet(Objet o) {
|
||||||
|
System.out.println("Avant :"+inventaire);
|
||||||
this.inventaire.remove(o);
|
this.inventaire.remove(o);
|
||||||
|
System.out.println("Après :"+inventaire);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,11 +84,7 @@ public class Personnage implements Inventaire {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getInventoryName() {
|
public String getInventoryName() {
|
||||||
return getInventoryNameFromPersoName(getNom());
|
return "Inventaire de "+getNom();
|
||||||
}
|
|
||||||
|
|
||||||
public static final String getInventoryNameFromPersoName(String persoName) {
|
|
||||||
return "Inventaire de "+persoName;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,17 +0,0 @@
|
|||||||
package com.bernard.murder.model.messages;
|
|
||||||
|
|
||||||
public class Message {
|
|
||||||
|
|
||||||
public String emmeteur;
|
|
||||||
public String texte;
|
|
||||||
public long sendTimestamp;
|
|
||||||
|
|
||||||
public Message(String emmeteur, String texte, long sendTimestamp) {
|
|
||||||
this.emmeteur = emmeteur;
|
|
||||||
this.texte = texte;
|
|
||||||
this.sendTimestamp = sendTimestamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,24 +0,0 @@
|
|||||||
package com.bernard.murder.model.messages;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class Thread {
|
|
||||||
|
|
||||||
public String joueur;
|
|
||||||
public long openTimestamp;
|
|
||||||
public String opAssigne;
|
|
||||||
public List<Message> messages;
|
|
||||||
public long closeTime = -1;
|
|
||||||
public long uid;
|
|
||||||
|
|
||||||
public Thread(String joueur, long openTimestamp, long uid) {
|
|
||||||
this.joueur = joueur;
|
|
||||||
this.openTimestamp = openTimestamp;
|
|
||||||
this.messages = new ArrayList<>();
|
|
||||||
this.uid = uid;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,16 +0,0 @@
|
|||||||
package com.bernard.murder.server;
|
|
||||||
|
|
||||||
public class Codes {
|
|
||||||
|
|
||||||
// NETWORKING
|
|
||||||
|
|
||||||
// [commande 1, UUID requestId]
|
|
||||||
public static final byte PING = 0x00;
|
|
||||||
public static final byte PONG = 0x01;
|
|
||||||
|
|
||||||
// [commande 1]
|
|
||||||
public static final byte ASK_PUBKEY = 0x02;
|
|
||||||
// [commande 1, byteCount int, byte[] key]
|
|
||||||
public static final byte GIVE_PUBKEY = 0x03;
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,12 +0,0 @@
|
|||||||
package com.bernard.murder.server;
|
|
||||||
|
|
||||||
import com.bernard.murder.audio.Serveur;
|
|
||||||
|
|
||||||
public class CommandedServer {
|
|
||||||
|
|
||||||
Serveur serveur;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,48 +0,0 @@
|
|||||||
package com.bernard.murder.server;
|
|
||||||
|
|
||||||
import java.net.SocketAddress;
|
|
||||||
import java.security.InvalidKeyException;
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
import java.security.PublicKey;
|
|
||||||
|
|
||||||
import javax.crypto.BadPaddingException;
|
|
||||||
import javax.crypto.Cipher;
|
|
||||||
import javax.crypto.IllegalBlockSizeException;
|
|
||||||
import javax.crypto.NoSuchPaddingException;
|
|
||||||
|
|
||||||
import com.bernard.murder.Parametres;
|
|
||||||
|
|
||||||
public class Device {
|
|
||||||
|
|
||||||
DeviceType type;
|
|
||||||
String nom;
|
|
||||||
|
|
||||||
PublicKey cle;
|
|
||||||
SocketAddress addresse;
|
|
||||||
|
|
||||||
public Device(DeviceType type, String nom, PublicKey cle, SocketAddress addresse) {
|
|
||||||
super();
|
|
||||||
this.type = type;
|
|
||||||
this.nom = nom;
|
|
||||||
this.cle = cle;
|
|
||||||
this.addresse = addresse;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] decryptReceivedMessage(byte[] message) {
|
|
||||||
try {
|
|
||||||
Cipher decodeur;
|
|
||||||
decodeur = Cipher.getInstance(Parametres.instance.encryptionAlg);
|
|
||||||
decodeur.init(Cipher.DECRYPT_MODE, this.cle);
|
|
||||||
|
|
||||||
return decodeur.doFinal(message);
|
|
||||||
} catch (NoSuchAlgorithmException |
|
|
||||||
NoSuchPaddingException |
|
|
||||||
InvalidKeyException |
|
|
||||||
IllegalBlockSizeException |
|
|
||||||
BadPaddingException e) {
|
|
||||||
throw new IllegalStateException("Impossible d'initialiser le décodeur pour l'appareil à l'adresse "+addresse.toString(),e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,31 +0,0 @@
|
|||||||
package com.bernard.murder.server;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
public enum DeviceType {
|
|
||||||
|
|
||||||
TerminalMaitre(0x00),
|
|
||||||
TerminalEsclave(0x01),
|
|
||||||
Microphone(0x10),
|
|
||||||
Enceinte(0x11),
|
|
||||||
JoueurPhone(0x20),
|
|
||||||
OpPhone(0x21);
|
|
||||||
|
|
||||||
private byte code;
|
|
||||||
|
|
||||||
private DeviceType(byte code) {
|
|
||||||
this.code = code;
|
|
||||||
}
|
|
||||||
private DeviceType(int code) {
|
|
||||||
this((byte)code);
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte getCode() {
|
|
||||||
return code;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static DeviceType of(byte code) {
|
|
||||||
return Arrays.stream(DeviceType.values()).filter(d -> d.getCode()==code).findAny().orElse(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,96 +0,0 @@
|
|||||||
package com.bernard.murder.server;
|
|
||||||
|
|
||||||
import java.net.InetSocketAddress;
|
|
||||||
import java.net.SocketAddress;
|
|
||||||
import java.net.SocketException;
|
|
||||||
import java.net.UnknownHostException;
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.security.InvalidKeyException;
|
|
||||||
import java.security.KeyPair;
|
|
||||||
import java.security.KeyPairGenerator;
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
import java.security.PrivateKey;
|
|
||||||
import java.security.SecureRandom;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.function.BiConsumer;
|
|
||||||
|
|
||||||
import javax.crypto.Cipher;
|
|
||||||
import javax.crypto.NoSuchPaddingException;
|
|
||||||
|
|
||||||
import com.bernard.murder.Parametres;
|
|
||||||
import com.bernard.murder.audio.Serveur;
|
|
||||||
|
|
||||||
public class ServeurMaitre {
|
|
||||||
|
|
||||||
private Serveur serveur;
|
|
||||||
|
|
||||||
private PrivateKey masterPrivateKey;
|
|
||||||
private Cipher encodeur;
|
|
||||||
|
|
||||||
private Map<SocketAddress,Device> devices;
|
|
||||||
|
|
||||||
|
|
||||||
public ServeurMaitre(String name, int port) throws UnknownHostException, SocketException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException {
|
|
||||||
serveur = new Serveur((BiConsumer<Object,SocketAddress>)(this::globalCommandReceiver), new InetSocketAddress(port));
|
|
||||||
|
|
||||||
SecureRandom srand = new SecureRandom();
|
|
||||||
KeyPairGenerator kpg = KeyPairGenerator.getInstance(Parametres.instance.encryptionAlg);
|
|
||||||
kpg.initialize(Parametres.instance.encryptionKeySize, srand);
|
|
||||||
|
|
||||||
KeyPair kpair = kpg.generateKeyPair();
|
|
||||||
this.masterPrivateKey = kpair.getPrivate();
|
|
||||||
|
|
||||||
// Renvoie une erreur si le cipher n'existe pas.
|
|
||||||
this.encodeur = Cipher.getInstance(Parametres.instance.encryptionAlg);
|
|
||||||
this.encodeur.init(Cipher.ENCRYPT_MODE, masterPrivateKey);
|
|
||||||
|
|
||||||
Device thisDevice = new Device(DeviceType.TerminalMaitre, name, kpair.getPublic(), serveur.getAddress());
|
|
||||||
|
|
||||||
devices = new HashMap<>();
|
|
||||||
devices.put(serveur.getAddress(), thisDevice);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
*
|
|
||||||
* Toutes les commandes sont encryptées avec la clé de l'envoyeur, sauf
|
|
||||||
* les commandes de ping et récupération de la clé publique du maître
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
public void globalCommandReceiver(Object untypedData, SocketAddress sender) {
|
|
||||||
byte[] data = (byte[]) untypedData;
|
|
||||||
if(devices.containsKey(sender)) {
|
|
||||||
// Alors on déchiffre avant de faire avaler.
|
|
||||||
Device sendingDevice = devices.get(sender);
|
|
||||||
|
|
||||||
byte[] realMessage = sendingDevice.decryptReceivedMessage(data);
|
|
||||||
|
|
||||||
uncryptedCommandReceiver(ByteBuffer.wrap(realMessage), sendingDevice);
|
|
||||||
|
|
||||||
}else {
|
|
||||||
// La commande ne dois pas être encryptée
|
|
||||||
ByteBuffer donnees = ByteBuffer.wrap(data);
|
|
||||||
byte commande = donnees.get();
|
|
||||||
switch(commande) {
|
|
||||||
case Codes.PING:
|
|
||||||
case Codes.PONG:
|
|
||||||
case Codes.ASK_PUBKEY:
|
|
||||||
//case Codes.GIVE_PUBKEY: Inutile pour le master, les clés sont données à l'enregistrement.
|
|
||||||
|
|
||||||
|
|
||||||
default:
|
|
||||||
System.err.println("J'ai reçu une commande qui devrait être encryptée !!!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void uncryptedCommandReceiver(ByteBuffer data, Device sender) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void audioCommandReceiver(ByteBuffer data, Device device) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -36,6 +36,7 @@ public class MouseReactiveTabbedPane extends JTabbedPane {
|
|||||||
@Override
|
@Override
|
||||||
public void dragOver(DropTargetDragEvent dtde) {
|
public void dragOver(DropTargetDragEvent dtde) {
|
||||||
int tab = getTab(dtde);
|
int tab = getTab(dtde);
|
||||||
|
System.out.println(">"+tab+"/"+hoverIndex+"-"+enteredTime);
|
||||||
if(tab==-1) {
|
if(tab==-1) {
|
||||||
enteredTime=-1;
|
enteredTime=-1;
|
||||||
hoverIndex=-1;
|
hoverIndex=-1;
|
||||||
|
|||||||
@ -1,315 +0,0 @@
|
|||||||
package com.bernard.murder.util.view;
|
|
||||||
|
|
||||||
import java.awt.*;
|
|
||||||
import javax.swing.*;
|
|
||||||
|
|
||||||
//Honteusement volé de https://tips4java.wordpress.com/2009/12/20/scrollable-panel/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A panel that implements the Scrollable interface. This class allows you to
|
|
||||||
* customize the scrollable features by using newly provided setter methods so
|
|
||||||
* you don't have to extend this class every time.
|
|
||||||
*
|
|
||||||
* Scrollable amounts can be specifed as a percentage of the viewport size or as
|
|
||||||
* an actual pixel value. The amount can be changed for both unit and block
|
|
||||||
* scrolling for both horizontal and vertical scrollbars.
|
|
||||||
*
|
|
||||||
* The Scrollable interface only provides a boolean value for determining
|
|
||||||
* whether or not the viewport size (width or height) should be used by the
|
|
||||||
* scrollpane when determining if scrollbars should be made visible. This class
|
|
||||||
* supports the concept of dynamically changing this value based on the size of
|
|
||||||
* the viewport. In this case the viewport size will only be used when it is
|
|
||||||
* larger than the panels size. This has the effect of ensuring the viewport is
|
|
||||||
* always full as components added to the panel will be size to fill the area
|
|
||||||
* available, based on the rules of the applicable layout manager of course.
|
|
||||||
*/
|
|
||||||
public class ScrollablePanel extends JPanel implements Scrollable, SwingConstants {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = -6250434641501235247L;
|
|
||||||
|
|
||||||
public enum ScrollableSizeHint {
|
|
||||||
NONE, FIT, STRETCH;
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum IncrementType {
|
|
||||||
PERCENT, PIXELS;
|
|
||||||
}
|
|
||||||
|
|
||||||
private ScrollableSizeHint scrollableHeight = ScrollableSizeHint.NONE;
|
|
||||||
private ScrollableSizeHint scrollableWidth = ScrollableSizeHint.NONE;
|
|
||||||
|
|
||||||
private IncrementInfo horizontalBlock;
|
|
||||||
private IncrementInfo horizontalUnit;
|
|
||||||
private IncrementInfo verticalBlock;
|
|
||||||
private IncrementInfo verticalUnit;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Default constructor that uses a FlowLayout
|
|
||||||
*/
|
|
||||||
public ScrollablePanel() {
|
|
||||||
this(new FlowLayout());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constuctor for specifying the LayoutManager of the panel.
|
|
||||||
*
|
|
||||||
* @param layout the LayoutManger for the panel
|
|
||||||
*/
|
|
||||||
public ScrollablePanel(LayoutManager layout) {
|
|
||||||
super(layout);
|
|
||||||
|
|
||||||
IncrementInfo block = new IncrementInfo(IncrementType.PERCENT, 100);
|
|
||||||
IncrementInfo unit = new IncrementInfo(IncrementType.PERCENT, 10);
|
|
||||||
|
|
||||||
setScrollableBlockIncrement(HORIZONTAL, block);
|
|
||||||
setScrollableBlockIncrement(VERTICAL, block);
|
|
||||||
setScrollableUnitIncrement(HORIZONTAL, unit);
|
|
||||||
setScrollableUnitIncrement(VERTICAL, unit);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the height ScrollableSizeHint enum
|
|
||||||
*
|
|
||||||
* @return the ScrollableSizeHint enum for the height
|
|
||||||
*/
|
|
||||||
public ScrollableSizeHint getScrollableHeight() {
|
|
||||||
return scrollableHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the ScrollableSizeHint enum for the height. The enum is used to determine
|
|
||||||
* the boolean value that is returned by the getScrollableTracksViewportHeight()
|
|
||||||
* method. The valid values are:
|
|
||||||
*
|
|
||||||
* ScrollableSizeHint.NONE - return "false", which causes the height of the
|
|
||||||
* panel to be used when laying out the children ScrollableSizeHint.FIT - return
|
|
||||||
* "true", which causes the height of the viewport to be used when laying out
|
|
||||||
* the children ScrollableSizeHint.STRETCH - return "true" when the viewport
|
|
||||||
* height is greater than the height of the panel, "false" otherwise.
|
|
||||||
*
|
|
||||||
* @param scrollableHeight as represented by the ScrollableSizeHint enum.
|
|
||||||
*/
|
|
||||||
public void setScrollableHeight(ScrollableSizeHint scrollableHeight) {
|
|
||||||
this.scrollableHeight = scrollableHeight;
|
|
||||||
revalidate();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the width ScrollableSizeHint enum
|
|
||||||
*
|
|
||||||
* @return the ScrollableSizeHint enum for the width
|
|
||||||
*/
|
|
||||||
public ScrollableSizeHint getScrollableWidth() {
|
|
||||||
return scrollableWidth;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the ScrollableSizeHint enum for the width. The enum is used to determine
|
|
||||||
* the boolean value that is returned by the getScrollableTracksViewportWidth()
|
|
||||||
* method. The valid values are:
|
|
||||||
*
|
|
||||||
* ScrollableSizeHint.NONE - return "false", which causes the width of the panel
|
|
||||||
* to be used when laying out the children ScrollableSizeHint.FIT - return
|
|
||||||
* "true", which causes the width of the viewport to be used when laying out the
|
|
||||||
* children ScrollableSizeHint.STRETCH - return "true" when the viewport width
|
|
||||||
* is greater than the width of the panel, "false" otherwise.
|
|
||||||
*
|
|
||||||
* @param scrollableWidth as represented by the ScrollableSizeHint enum.
|
|
||||||
*/
|
|
||||||
public void setScrollableWidth(ScrollableSizeHint scrollableWidth) {
|
|
||||||
this.scrollableWidth = scrollableWidth;
|
|
||||||
revalidate();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the block IncrementInfo for the specified orientation
|
|
||||||
*
|
|
||||||
* @return the block IncrementInfo for the specified orientation
|
|
||||||
*/
|
|
||||||
public IncrementInfo getScrollableBlockIncrement(int orientation) {
|
|
||||||
return orientation == SwingConstants.HORIZONTAL ? horizontalBlock : verticalBlock;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Specify the information needed to do block scrolling.
|
|
||||||
*
|
|
||||||
* @param orientation specify the scrolling orientation. Must be either:
|
|
||||||
* SwingContants.HORIZONTAL or SwingContants.VERTICAL.
|
|
||||||
* @paran type specify how the amount parameter in the calculation of the
|
|
||||||
* scrollable amount. Valid values are: IncrementType.PERCENT - treat the
|
|
||||||
* amount as a % of the viewport size IncrementType.PIXEL - treat the
|
|
||||||
* amount as the scrollable amount
|
|
||||||
* @param amount a value used with the IncrementType to determine the scrollable
|
|
||||||
* amount
|
|
||||||
*/
|
|
||||||
public void setScrollableBlockIncrement(int orientation, IncrementType type, int amount) {
|
|
||||||
IncrementInfo info = new IncrementInfo(type, amount);
|
|
||||||
setScrollableBlockIncrement(orientation, info);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Specify the information needed to do block scrolling.
|
|
||||||
*
|
|
||||||
* @param orientation specify the scrolling orientation. Must be either:
|
|
||||||
* SwingContants.HORIZONTAL or SwingContants.VERTICAL.
|
|
||||||
* @param info An IncrementInfo object containing information of how to
|
|
||||||
* calculate the scrollable amount.
|
|
||||||
*/
|
|
||||||
public void setScrollableBlockIncrement(int orientation, IncrementInfo info) {
|
|
||||||
switch (orientation) {
|
|
||||||
case SwingConstants.HORIZONTAL:
|
|
||||||
horizontalBlock = info;
|
|
||||||
break;
|
|
||||||
case SwingConstants.VERTICAL:
|
|
||||||
verticalBlock = info;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new IllegalArgumentException("Invalid orientation: " + orientation);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the unit IncrementInfo for the specified orientation
|
|
||||||
*
|
|
||||||
* @return the unit IncrementInfo for the specified orientation
|
|
||||||
*/
|
|
||||||
public IncrementInfo getScrollableUnitIncrement(int orientation) {
|
|
||||||
return orientation == SwingConstants.HORIZONTAL ? horizontalUnit : verticalUnit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Specify the information needed to do unit scrolling.
|
|
||||||
*
|
|
||||||
* @param orientation specify the scrolling orientation. Must be either:
|
|
||||||
* SwingContants.HORIZONTAL or SwingContants.VERTICAL.
|
|
||||||
* @paran type specify how the amount parameter in the calculation of the
|
|
||||||
* scrollable amount. Valid values are: IncrementType.PERCENT - treat the
|
|
||||||
* amount as a % of the viewport size IncrementType.PIXEL - treat the
|
|
||||||
* amount as the scrollable amount
|
|
||||||
* @param amount a value used with the IncrementType to determine the scrollable
|
|
||||||
* amount
|
|
||||||
*/
|
|
||||||
public void setScrollableUnitIncrement(int orientation, IncrementType type, int amount) {
|
|
||||||
IncrementInfo info = new IncrementInfo(type, amount);
|
|
||||||
setScrollableUnitIncrement(orientation, info);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Specify the information needed to do unit scrolling.
|
|
||||||
*
|
|
||||||
* @param orientation specify the scrolling orientation. Must be either:
|
|
||||||
* SwingContants.HORIZONTAL or SwingContants.VERTICAL.
|
|
||||||
* @param info An IncrementInfo object containing information of how to
|
|
||||||
* calculate the scrollable amount.
|
|
||||||
*/
|
|
||||||
public void setScrollableUnitIncrement(int orientation, IncrementInfo info) {
|
|
||||||
switch (orientation) {
|
|
||||||
case SwingConstants.HORIZONTAL:
|
|
||||||
horizontalUnit = info;
|
|
||||||
break;
|
|
||||||
case SwingConstants.VERTICAL:
|
|
||||||
verticalUnit = info;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new IllegalArgumentException("Invalid orientation: " + orientation);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Implement Scrollable interface
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Dimension getPreferredScrollableViewportSize() {
|
|
||||||
return getPreferredSize();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getScrollableUnitIncrement(Rectangle visible, int orientation, int direction) {
|
|
||||||
switch (orientation) {
|
|
||||||
case SwingConstants.HORIZONTAL:
|
|
||||||
return getScrollableIncrement(horizontalUnit, visible.width);
|
|
||||||
case SwingConstants.VERTICAL:
|
|
||||||
return getScrollableIncrement(verticalUnit, visible.height);
|
|
||||||
default:
|
|
||||||
throw new IllegalArgumentException("Invalid orientation: " + orientation);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getScrollableBlockIncrement(Rectangle visible, int orientation, int direction) {
|
|
||||||
switch (orientation) {
|
|
||||||
case SwingConstants.HORIZONTAL:
|
|
||||||
return getScrollableIncrement(horizontalBlock, visible.width);
|
|
||||||
case SwingConstants.VERTICAL:
|
|
||||||
return getScrollableIncrement(verticalBlock, visible.height);
|
|
||||||
default:
|
|
||||||
throw new IllegalArgumentException("Invalid orientation: " + orientation);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected int getScrollableIncrement(IncrementInfo info, int distance) {
|
|
||||||
if (info.getIncrement() == IncrementType.PIXELS)
|
|
||||||
return info.getAmount();
|
|
||||||
else
|
|
||||||
return distance * info.getAmount() / 100;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean getScrollableTracksViewportWidth() {
|
|
||||||
if (scrollableWidth == ScrollableSizeHint.NONE)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (scrollableWidth == ScrollableSizeHint.FIT)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// STRETCH sizing, use the greater of the panel or viewport width
|
|
||||||
|
|
||||||
if (getParent() instanceof JViewport) {
|
|
||||||
return (((JViewport) getParent()).getWidth() > getPreferredSize().width);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean getScrollableTracksViewportHeight() {
|
|
||||||
if (scrollableHeight == ScrollableSizeHint.NONE)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (scrollableHeight == ScrollableSizeHint.FIT)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// STRETCH sizing, use the greater of the panel or viewport height
|
|
||||||
|
|
||||||
if (getParent() instanceof JViewport) {
|
|
||||||
return (((JViewport) getParent()).getHeight() > getPreferredSize().height);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper class to hold the information required to calculate the scroll amount.
|
|
||||||
*/
|
|
||||||
static class IncrementInfo {
|
|
||||||
private IncrementType type;
|
|
||||||
private int amount;
|
|
||||||
|
|
||||||
public IncrementInfo(IncrementType type, int amount) {
|
|
||||||
this.type = type;
|
|
||||||
this.amount = amount;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IncrementType getIncrement() {
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getAmount() {
|
|
||||||
return amount;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "ScrollablePanel[" + type + ", " + amount + "]";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,9 +1,7 @@
|
|||||||
package com.bernard.murder.view;
|
package com.bernard.murder.view;
|
||||||
|
|
||||||
import java.awt.BorderLayout;
|
import java.awt.BorderLayout;
|
||||||
import java.awt.Container;
|
|
||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
import java.awt.GridLayout;
|
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -15,20 +13,13 @@ import javax.sound.sampled.LineUnavailableException;
|
|||||||
import javax.sound.sampled.Mixer;
|
import javax.sound.sampled.Mixer;
|
||||||
import javax.sound.sampled.Mixer.Info;
|
import javax.sound.sampled.Mixer.Info;
|
||||||
import javax.sound.sampled.SourceDataLine;
|
import javax.sound.sampled.SourceDataLine;
|
||||||
import javax.swing.BorderFactory;
|
|
||||||
import javax.swing.DefaultListModel;
|
|
||||||
import javax.swing.JButton;
|
import javax.swing.JButton;
|
||||||
import javax.swing.JFrame;
|
import javax.swing.JFrame;
|
||||||
import javax.swing.JList;
|
import javax.swing.JList;
|
||||||
import javax.swing.JPanel;
|
import javax.swing.JPanel;
|
||||||
import javax.swing.JScrollPane;
|
|
||||||
import javax.swing.JTextField;
|
import javax.swing.JTextField;
|
||||||
import javax.swing.ListSelectionModel;
|
|
||||||
import javax.swing.border.EmptyBorder;
|
|
||||||
import javax.swing.event.ListSelectionEvent;
|
|
||||||
import javax.swing.event.ListSelectionListener;
|
|
||||||
|
|
||||||
import com.bernard.murder.audio.Codes;
|
import com.bernard.murder.audio.AudioServer;
|
||||||
import com.bernard.murder.audio.SpeakerServer;
|
import com.bernard.murder.audio.SpeakerServer;
|
||||||
|
|
||||||
public class EnceinteServeurFrame extends JFrame{
|
public class EnceinteServeurFrame extends JFrame{
|
||||||
@ -37,34 +28,35 @@ public class EnceinteServeurFrame extends JFrame{
|
|||||||
|
|
||||||
SpeakerServer serveur;
|
SpeakerServer serveur;
|
||||||
String deviceName;
|
String deviceName;
|
||||||
NamedMicrophone[] micarray;
|
|
||||||
|
|
||||||
public EnceinteServeurFrame(String deviceName) {
|
public EnceinteServeurFrame(String deviceName) {
|
||||||
this.setSize(300, 500);
|
this.setSize(300, 500);
|
||||||
this.setMinimumSize(new Dimension(100, 200));
|
this.setMinimumSize(new Dimension(100, 200));
|
||||||
this.setLocationRelativeTo(null);
|
this.setLocationRelativeTo(null);
|
||||||
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
|
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
|
||||||
this.setTitle("Serveur audio: Enceinte");
|
this.setTitle("Serveur audio");
|
||||||
this.deviceName = deviceName;
|
this.deviceName = deviceName;
|
||||||
|
|
||||||
this.setContentPane(genContentPan());
|
this.setContentPane(genContentPan());
|
||||||
this.setVisible(true);
|
this.setVisible(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Container genContentPan() {
|
public JPanel genContentPan() {
|
||||||
JPanel panel = new JPanel(new BorderLayout());
|
JPanel panel = new JPanel(new BorderLayout());
|
||||||
panel.setBorder(new EmptyBorder(3, 3, 3, 3));
|
|
||||||
|
|
||||||
|
|
||||||
InformedSourceDataline[] marray = getEnceinteList();
|
InformedSourceDataline[] marray = getEnceinteList();
|
||||||
JList<InformedSourceDataline> enceinteListe = new JList<InformedSourceDataline>(marray);
|
JList<InformedSourceDataline> enceinteListe = new JList<InformedSourceDataline>(marray);
|
||||||
enceinteListe.setOpaque(false);
|
|
||||||
|
|
||||||
JTextField masterIP = new JTextField("192.168.1.1",15);
|
|
||||||
|
JPanel masterPanel = new JPanel(new BorderLayout());
|
||||||
|
JTextField masterIP = new JTextField("192.168.1.1");
|
||||||
JButton serverControl = new JButton("Lancer");
|
JButton serverControl = new JButton("Lancer");
|
||||||
|
masterPanel.add(serverControl,BorderLayout.EAST);
|
||||||
|
masterPanel.add(masterIP,BorderLayout.CENTER);
|
||||||
|
|
||||||
JList<NamedMicrophone> mics = new JList<>();
|
JList<NamedMicrophone> mics = new JList<>();
|
||||||
mics.setOpaque(false);
|
|
||||||
JButton silenceButton = new JButton("Silence");
|
|
||||||
|
|
||||||
serverControl.addActionListener(e->{
|
serverControl.addActionListener(e->{
|
||||||
if(enceinteListe.getSelectedValue()==null)return;
|
if(enceinteListe.getSelectedValue()==null)return;
|
||||||
@ -72,77 +64,24 @@ public class EnceinteServeurFrame extends JFrame{
|
|||||||
if(serveur!=null) {
|
if(serveur!=null) {
|
||||||
serveur.dispose();
|
serveur.dispose();
|
||||||
serveur = null;
|
serveur = null;
|
||||||
masterIP.setEnabled(true);
|
|
||||||
mics.setModel(new DefaultListModel<>());
|
|
||||||
serverControl.setText("Lancer");
|
serverControl.setText("Lancer");
|
||||||
}else {
|
}else {
|
||||||
serveur = new SpeakerServer(new InetSocketAddress(masterIP.getText(), Codes.communicationPort), deviceName,enceinteListe.getSelectedValue().tdl);
|
serveur = new SpeakerServer(new InetSocketAddress(masterIP.getText(), AudioServer.communicationPort), deviceName,enceinteListe.getSelectedValue().tdl);
|
||||||
masterIP.setEnabled(false);
|
|
||||||
serveur.setServerAnswered(()->{
|
serveur.setServerAnswered(()->{
|
||||||
serverControl.setText("Arrêter");
|
serverControl.setText("Arrêter");
|
||||||
});
|
List<NamedMicrophone> list = serveur.getAudioList().entrySet().stream().map(et -> new NamedMicrophone(et.getKey(), et.getValue())).collect(Collectors.toList());
|
||||||
serveur.addMicListUpdateListener(m -> {
|
NamedMicrophone[] micarray = new NamedMicrophone[list.size()];
|
||||||
List<NamedMicrophone> list = m.entrySet().stream().map(et -> new NamedMicrophone(et.getKey(), et.getValue())).collect(Collectors.toList());
|
|
||||||
micarray = new NamedMicrophone[list.size()];
|
|
||||||
list.toArray(micarray);
|
list.toArray(micarray);
|
||||||
mics.setListData(micarray);
|
mics.setListData(micarray);
|
||||||
System.out.println("Micros chargés: "+list);
|
|
||||||
});
|
|
||||||
serveur.addDisconnectListener(()->{
|
|
||||||
// Le dispose a été fait
|
|
||||||
serveur = null;
|
|
||||||
masterIP.setEnabled(true);
|
|
||||||
serverControl.setText("Lancer");
|
|
||||||
});
|
|
||||||
serveur.addBrokenMicListener(()->{
|
|
||||||
//XXX Test si ca fonctionne, si ca déclenche bien le listener.
|
|
||||||
mics.clearSelection();
|
|
||||||
serveur.askStopStreaming();
|
|
||||||
});
|
});
|
||||||
serverControl.setText("Lancement");
|
serverControl.setText("Lancement");
|
||||||
}
|
}
|
||||||
serverControl.setEnabled(true);
|
serverControl.setEnabled(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
mics.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
panel.add(masterPanel,BorderLayout.NORTH);
|
||||||
|
panel.add(mics,BorderLayout.SOUTH);
|
||||||
mics.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
|
panel.add(enceinteListe,BorderLayout.CENTER);
|
||||||
|
|
||||||
@Override
|
|
||||||
public void valueChanged(ListSelectionEvent e) {
|
|
||||||
int i = e.getFirstIndex();
|
|
||||||
boolean wantToListen=mics.isSelectedIndex(i);
|
|
||||||
if(wantToListen && serveur != null)
|
|
||||||
serveur.askForStream(micarray[i].micId);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
silenceButton.addActionListener(e -> {
|
|
||||||
mics.clearSelection();
|
|
||||||
if(serveur!=null)
|
|
||||||
serveur.askStopStreaming();
|
|
||||||
});
|
|
||||||
|
|
||||||
JScrollPane jE = new JScrollPane(enceinteListe);
|
|
||||||
jE.setBorder(BorderFactory.createTitledBorder("Enceintes disponibles"));
|
|
||||||
JScrollPane jM = new JScrollPane(mics);
|
|
||||||
jM.setBorder(BorderFactory.createTitledBorder("Microphones à écouter"));
|
|
||||||
|
|
||||||
|
|
||||||
JPanel headP = new JPanel(new BorderLayout());
|
|
||||||
headP.setBorder(new EmptyBorder(3, 3, 5, 3));
|
|
||||||
|
|
||||||
JPanel centerP = new JPanel(new GridLayout(2, 1));
|
|
||||||
|
|
||||||
headP.add(serverControl,BorderLayout.EAST);
|
|
||||||
headP.add(masterIP,BorderLayout.CENTER);
|
|
||||||
centerP.add(jE);
|
|
||||||
centerP.add(jM);
|
|
||||||
|
|
||||||
panel.add(headP,BorderLayout.NORTH);
|
|
||||||
panel.add(centerP,BorderLayout.CENTER);
|
|
||||||
panel.add(silenceButton,BorderLayout.SOUTH);
|
|
||||||
|
|
||||||
return panel;
|
return panel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -65,6 +65,7 @@ public class HoverSelect implements DropTargetListener,Runnable{
|
|||||||
@Override
|
@Override
|
||||||
public void dragEnter(DropTargetDragEvent e) {
|
public void dragEnter(DropTargetDragEvent e) {
|
||||||
enteredTime = System.nanoTime();
|
enteredTime = System.nanoTime();
|
||||||
|
System.out.println("entré");
|
||||||
plannedThread = new Thread(()-> {
|
plannedThread = new Thread(()-> {
|
||||||
try {
|
try {
|
||||||
Thread.sleep(waitTime/1_000_000, (int)(waitTime%1_000_000));
|
Thread.sleep(waitTime/1_000_000, (int)(waitTime%1_000_000));
|
||||||
@ -90,6 +91,7 @@ public class HoverSelect implements DropTargetListener,Runnable{
|
|||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
enteredTime = System.nanoTime();
|
enteredTime = System.nanoTime();
|
||||||
|
System.out.println("entré");
|
||||||
plannedThread = new Thread(()-> {
|
plannedThread = new Thread(()-> {
|
||||||
try {
|
try {
|
||||||
Thread.sleep(waitTime/1_000_000, (int)(waitTime%1_000_000));
|
Thread.sleep(waitTime/1_000_000, (int)(waitTime%1_000_000));
|
||||||
|
|||||||
@ -2,8 +2,6 @@ package com.bernard.murder.view;
|
|||||||
|
|
||||||
import java.awt.GridLayout;
|
import java.awt.GridLayout;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileWriter;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.text.DateFormat;
|
import java.text.DateFormat;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -17,80 +15,25 @@ import javax.swing.JPanel;
|
|||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
import javax.swing.UnsupportedLookAndFeelException;
|
import javax.swing.UnsupportedLookAndFeelException;
|
||||||
|
|
||||||
import com.amihaiemil.eoyaml.Yaml;
|
|
||||||
import com.amihaiemil.eoyaml.YamlNode;
|
|
||||||
import com.amihaiemil.eoyaml.YamlPrinter;
|
|
||||||
import com.bernard.configurator.Configurator;
|
|
||||||
import com.bernard.murder.Parametres;
|
|
||||||
import com.bernard.murder.game.GameCreator;
|
import com.bernard.murder.game.GameCreator;
|
||||||
import com.bernard.murder.game.GameCreator.QuicksavedPartie;
|
import com.bernard.murder.game.GameCreator.QuicksavedPartie;
|
||||||
import com.bernard.murder.game.GameManager;
|
import com.bernard.murder.game.GameManager;
|
||||||
import com.bernard.murder.model.Partie;
|
import com.bernard.murder.model.Partie;
|
||||||
import com.bernard.murder.model.Personnage;
|
import com.bernard.murder.model.Personnage;
|
||||||
import com.bernard.murder.view.minel.Minel;
|
import com.bernard.murder.view.minel.Minel;
|
||||||
import com.formdev.flatlaf.FlatDarculaLaf;
|
|
||||||
import com.formdev.flatlaf.FlatDarkLaf;
|
|
||||||
import com.formdev.flatlaf.FlatIntelliJLaf;
|
|
||||||
import com.formdev.flatlaf.FlatLightLaf;
|
|
||||||
|
|
||||||
public class LauncherFrame extends JFrame{
|
public class LauncherFrame extends JFrame{
|
||||||
|
|
||||||
private static final long serialVersionUID = 5831232688024137883L;
|
private static final long serialVersionUID = 5831232688024137883L;
|
||||||
|
|
||||||
public static final String paramPath = "./murderator-config.yml";
|
|
||||||
|
|
||||||
public static void main2(String[] args) throws IOException {
|
|
||||||
File test = new File("/tmp/test.yml");
|
|
||||||
YamlPrinter yp = Yaml.createYamlPrinter(new FileWriter(test));
|
|
||||||
YamlNode theNode = Configurator.objectToNode(new Parametres());
|
|
||||||
System.out.println(theNode);
|
|
||||||
yp.print(theNode);
|
|
||||||
System.out.println("--------------------------------------------");
|
|
||||||
System.out.println("On tente de relire ...");
|
|
||||||
Parametres params = Configurator.readYaml(theNode, Parametres.class);
|
|
||||||
System.out.println(params);
|
|
||||||
System.out.println("Terminé !");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
try {
|
|
||||||
File paramFile = new File(LauncherFrame.paramPath);
|
|
||||||
if(!paramFile.exists()) {
|
|
||||||
try {
|
|
||||||
YamlPrinter yp = Yaml.createYamlPrinter(new FileWriter(paramFile));
|
|
||||||
yp.print(Configurator.objectToNode(new Parametres()));
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
YamlNode theConf = Yaml.createYamlInput(paramFile).readYamlMapping();
|
|
||||||
Parametres.instance = (Parametres)Configurator.readYaml(theConf, Parametres.class);
|
|
||||||
} catch (Exception e) {
|
|
||||||
System.err.println("Impossible de lire les paramètres, on tombe sur les défauts.");
|
|
||||||
e.printStackTrace();
|
|
||||||
Parametres.instance = new Parametres();
|
|
||||||
}
|
|
||||||
new LauncherFrame();
|
new LauncherFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
public LauncherFrame() {
|
public LauncherFrame() {
|
||||||
try {
|
try {
|
||||||
//TODO implement flatlaf look&feel
|
//TODO implement flatlaf look&feel
|
||||||
if(Parametres.instance.lookAndFeel==null)
|
|
||||||
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
|
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
|
||||||
else
|
|
||||||
switch(Parametres.instance.lookAndFeel) {
|
|
||||||
case "flatlaf-light":
|
|
||||||
FlatLightLaf.setup();break;
|
|
||||||
case "flatlaf-dark":
|
|
||||||
FlatDarkLaf.setup();break;
|
|
||||||
case "flatlaf-intelliJ":
|
|
||||||
FlatIntelliJLaf.setup();break;
|
|
||||||
case "flatlaf-darcula":
|
|
||||||
FlatDarculaLaf.setup();break;
|
|
||||||
default:
|
|
||||||
UIManager.setLookAndFeel(Parametres.instance.lookAndFeel);
|
|
||||||
}
|
|
||||||
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException e1) {
|
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException e1) {
|
||||||
e1.printStackTrace();
|
e1.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,16 +12,13 @@ import javax.sound.sampled.LineUnavailableException;
|
|||||||
import javax.sound.sampled.Mixer;
|
import javax.sound.sampled.Mixer;
|
||||||
import javax.sound.sampled.Mixer.Info;
|
import javax.sound.sampled.Mixer.Info;
|
||||||
import javax.sound.sampled.TargetDataLine;
|
import javax.sound.sampled.TargetDataLine;
|
||||||
import javax.swing.BorderFactory;
|
|
||||||
import javax.swing.JButton;
|
import javax.swing.JButton;
|
||||||
import javax.swing.JFrame;
|
import javax.swing.JFrame;
|
||||||
import javax.swing.JList;
|
import javax.swing.JList;
|
||||||
import javax.swing.JPanel;
|
import javax.swing.JPanel;
|
||||||
import javax.swing.JScrollPane;
|
|
||||||
import javax.swing.JTextField;
|
import javax.swing.JTextField;
|
||||||
import javax.swing.border.EmptyBorder;
|
|
||||||
|
|
||||||
import com.bernard.murder.audio.Codes;
|
import com.bernard.murder.audio.AudioServer;
|
||||||
import com.bernard.murder.audio.MicServer;
|
import com.bernard.murder.audio.MicServer;
|
||||||
|
|
||||||
public class MicServeurFrame extends JFrame{
|
public class MicServeurFrame extends JFrame{
|
||||||
@ -32,11 +29,11 @@ public class MicServeurFrame extends JFrame{
|
|||||||
String deviceName;
|
String deviceName;
|
||||||
|
|
||||||
public MicServeurFrame(String deviceName) {
|
public MicServeurFrame(String deviceName) {
|
||||||
this.setSize(800, 300);
|
this.setSize(300, 500);
|
||||||
this.setMinimumSize(new Dimension(100, 200));
|
this.setMinimumSize(new Dimension(100, 200));
|
||||||
this.setLocationRelativeTo(null);
|
this.setLocationRelativeTo(null);
|
||||||
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
|
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
|
||||||
this.setTitle("Serveur audio: Microphone");
|
this.setTitle("Serveur audio");
|
||||||
this.deviceName = deviceName;
|
this.deviceName = deviceName;
|
||||||
|
|
||||||
this.setContentPane(genContentPan());
|
this.setContentPane(genContentPan());
|
||||||
@ -44,15 +41,13 @@ public class MicServeurFrame extends JFrame{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public JPanel genContentPan() {
|
public JPanel genContentPan() {
|
||||||
|
|
||||||
JPanel panel = new JPanel(new BorderLayout());
|
JPanel panel = new JPanel(new BorderLayout());
|
||||||
panel.setBorder(new EmptyBorder(3, 3, 3, 3));
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
InformedTargetDataline[] marray = getEnceinteList();
|
InformedTargetDataline[] marray = getEnceinteList();
|
||||||
JList<InformedTargetDataline> micListe = new JList<InformedTargetDataline>(marray);
|
JList<InformedTargetDataline> micListe = new JList<InformedTargetDataline>(marray);
|
||||||
micListe.setOpaque(false);
|
|
||||||
|
|
||||||
JPanel masterPanel = new JPanel(new BorderLayout());
|
JPanel masterPanel = new JPanel(new BorderLayout());
|
||||||
JTextField masterIP = new JTextField("192.168.1.1");
|
JTextField masterIP = new JTextField("192.168.1.1");
|
||||||
@ -66,38 +61,19 @@ public class MicServeurFrame extends JFrame{
|
|||||||
if(serveur!=null) {
|
if(serveur!=null) {
|
||||||
serveur.dispose();
|
serveur.dispose();
|
||||||
serveur = null;
|
serveur = null;
|
||||||
masterIP.setEnabled(true);
|
|
||||||
serverControl.setText("Lancer");
|
serverControl.setText("Lancer");
|
||||||
}else {
|
}else {
|
||||||
masterIP.setEnabled(false);
|
serveur = new MicServer(new InetSocketAddress(masterIP.getText(), AudioServer.communicationPort), deviceName,micListe.getSelectedValue().tdl);
|
||||||
serveur = new MicServer(new InetSocketAddress(masterIP.getText(), Codes.communicationPort), deviceName,micListe.getSelectedValue().tdl);
|
|
||||||
serveur.setServerAnswered(()->{
|
serveur.setServerAnswered(()->{
|
||||||
serverControl.setText("Arrêter");
|
serverControl.setText("Arrêter");
|
||||||
});
|
});
|
||||||
serveur.addDisconnectListener(()->{
|
|
||||||
// Le dispose a été fait
|
|
||||||
serveur = null;
|
|
||||||
masterIP.setEnabled(true);
|
|
||||||
serverControl.setText("Lancer");
|
|
||||||
});
|
|
||||||
serverControl.setText("Lancement");
|
serverControl.setText("Lancement");
|
||||||
}
|
}
|
||||||
serverControl.setEnabled(true);
|
serverControl.setEnabled(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
JScrollPane jE = new JScrollPane(micListe);
|
panel.add(masterPanel,BorderLayout.NORTH);
|
||||||
jE.setBorder(BorderFactory.createTitledBorder("Microphones disponibles"));
|
panel.add(micListe,BorderLayout.CENTER);
|
||||||
|
|
||||||
|
|
||||||
JPanel headP = new JPanel(new BorderLayout());
|
|
||||||
headP.setBorder(new EmptyBorder(3, 3, 5, 3));
|
|
||||||
|
|
||||||
headP.add(serverControl,BorderLayout.EAST);
|
|
||||||
headP.add(masterIP,BorderLayout.CENTER);
|
|
||||||
|
|
||||||
panel.add(headP,BorderLayout.NORTH);
|
|
||||||
panel.add(jE,BorderLayout.CENTER);
|
|
||||||
|
|
||||||
return panel;
|
return panel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -14,6 +14,7 @@ import com.amihaiemil.eoyaml.YamlMapping;
|
|||||||
import com.amihaiemil.eoyaml.YamlMappingBuilder;
|
import com.amihaiemil.eoyaml.YamlMappingBuilder;
|
||||||
import com.amihaiemil.eoyaml.YamlNode;
|
import com.amihaiemil.eoyaml.YamlNode;
|
||||||
import com.amihaiemil.eoyaml.YamlSequence;
|
import com.amihaiemil.eoyaml.YamlSequence;
|
||||||
|
import com.bernard.murder.YamlUtils;
|
||||||
import com.bernard.murder.game.GameCreator.QuicksavedPartie;
|
import com.bernard.murder.game.GameCreator.QuicksavedPartie;
|
||||||
import com.bernard.murder.game.GameManager;
|
import com.bernard.murder.game.GameManager;
|
||||||
import com.bernard.murder.model.Partie;
|
import com.bernard.murder.model.Partie;
|
||||||
@ -24,7 +25,6 @@ import com.bernard.murder.view.minel.Minel;
|
|||||||
import com.bernard.murder.view.minel.ObjetSearchMinel;
|
import com.bernard.murder.view.minel.ObjetSearchMinel;
|
||||||
import com.bernard.murder.view.minel.ServeurMinel;
|
import com.bernard.murder.view.minel.ServeurMinel;
|
||||||
import com.bernard.murder.view.minel.TextPanMinel;
|
import com.bernard.murder.view.minel.TextPanMinel;
|
||||||
import com.bernard.util.YamlUtils;
|
|
||||||
|
|
||||||
public class MinelsCreator {
|
public class MinelsCreator {
|
||||||
|
|
||||||
@ -35,6 +35,7 @@ public class MinelsCreator {
|
|||||||
|
|
||||||
List<Minel> piecesMinels = new ArrayList<>();
|
List<Minel> piecesMinels = new ArrayList<>();
|
||||||
qpartie.piecesStream().map(p -> new InventaireMinel(manager, p)).forEach(m -> piecesMinels.add(m));
|
qpartie.piecesStream().map(p -> new InventaireMinel(manager, p)).forEach(m -> piecesMinels.add(m));
|
||||||
|
|
||||||
generalMinels.add(new TextPanMinel(manager));
|
generalMinels.add(new TextPanMinel(manager));
|
||||||
generalMinels.add(new ObjetSearchMinel(manager, manager.getEveryInventaire()));
|
generalMinels.add(new ObjetSearchMinel(manager, manager.getEveryInventaire()));
|
||||||
generalMinels.add(new ServeurMinel(manager));
|
generalMinels.add(new ServeurMinel(manager));
|
||||||
@ -141,9 +142,4 @@ public class MinelsCreator {
|
|||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void closeMiniels(Map<Personnage, List<Minel>> persoMinels, Map<String, List<Minel>> supMinels) {
|
|
||||||
persoMinels.values().stream().forEach(l -> l.forEach(Minel::onFrameClose));
|
|
||||||
supMinels .values().stream().forEach(l -> l.forEach(Minel::onFrameClose));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,27 +3,22 @@ package com.bernard.murder.view;
|
|||||||
import java.awt.BorderLayout;
|
import java.awt.BorderLayout;
|
||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
import java.awt.GridLayout;
|
import java.awt.GridLayout;
|
||||||
import java.awt.event.WindowAdapter;
|
|
||||||
import java.awt.event.WindowEvent;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import javax.swing.BorderFactory;
|
import javax.swing.BorderFactory;
|
||||||
import javax.swing.JFrame;
|
import javax.swing.JFrame;
|
||||||
import javax.swing.JOptionPane;
|
|
||||||
import javax.swing.JPanel;
|
import javax.swing.JPanel;
|
||||||
import javax.swing.JScrollPane;
|
import javax.swing.JScrollPane;
|
||||||
import javax.swing.JTabbedPane;
|
import javax.swing.JTabbedPane;
|
||||||
|
|
||||||
import com.bernard.murder.Parametres;
|
import com.bernard.murder.ParseUtils;
|
||||||
import com.bernard.murder.game.GameCreator.QuicksavedPartie;
|
import com.bernard.murder.game.GameCreator.QuicksavedPartie;
|
||||||
import com.bernard.murder.game.GameManager;
|
import com.bernard.murder.game.GameManager;
|
||||||
import com.bernard.murder.model.Partie;
|
import com.bernard.murder.model.Partie;
|
||||||
import com.bernard.murder.model.Personnage;
|
import com.bernard.murder.model.Personnage;
|
||||||
import com.bernard.murder.util.view.MouseReactiveTabbedPane;
|
import com.bernard.murder.util.view.MouseReactiveTabbedPane;
|
||||||
import com.bernard.murder.util.view.ScrollablePanel;
|
|
||||||
import com.bernard.murder.view.minel.Minel;
|
import com.bernard.murder.view.minel.Minel;
|
||||||
import com.bernard.util.ParseUtils;
|
|
||||||
|
|
||||||
public class MurderatorGameFrame extends JFrame{
|
public class MurderatorGameFrame extends JFrame{
|
||||||
|
|
||||||
@ -33,21 +28,17 @@ public class MurderatorGameFrame extends JFrame{
|
|||||||
Map<String,List<Minel>> minelsSup;
|
Map<String,List<Minel>> minelsSup;
|
||||||
Map<Personnage,List<Minel>> minels;
|
Map<Personnage,List<Minel>> minels;
|
||||||
|
|
||||||
GameManager manager;
|
|
||||||
|
|
||||||
public MurderatorGameFrame(String frameName, Partie partie, GameManager manager,Map<String,List<Minel>> minelsSup,Map<Personnage,List<Minel>> minels) {
|
public MurderatorGameFrame(String frameName, Partie partie, GameManager manager,Map<String,List<Minel>> minelsSup,Map<Personnage,List<Minel>> minels) {
|
||||||
this.setSize(700, 500);
|
this.setSize(700, 500);
|
||||||
this.setMinimumSize(new Dimension(200, 100));
|
this.setMinimumSize(new Dimension(200, 100));
|
||||||
this.setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
|
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
|
||||||
this.setTitle(frameName);
|
this.setTitle(frameName);
|
||||||
this.minelsSup = minelsSup;
|
this.minelsSup = minelsSup;
|
||||||
this.minels = minels;
|
this.minels = minels;
|
||||||
this.manager = manager;
|
|
||||||
manager.bindMinelQuicksaver(() -> MinelsCreator.createMinelQuicksave(minels, minelsSup));
|
manager.bindMinelQuicksaver(() -> MinelsCreator.createMinelQuicksave(minels, minelsSup));
|
||||||
|
|
||||||
this.setContentPane(genGamePane(partie,manager,minelsSup,minels));
|
this.setContentPane(genGamePane(partie,manager,minelsSup,minels));
|
||||||
this.addWindowListener(new WListener());
|
this.pack();
|
||||||
//this.pack();
|
|
||||||
this.setLocationRelativeTo(null);
|
this.setLocationRelativeTo(null);
|
||||||
this.setVisible(true);
|
this.setVisible(true);
|
||||||
}
|
}
|
||||||
@ -61,88 +52,71 @@ public class MurderatorGameFrame extends JFrame{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public JPanel genGamePane(Partie partie,GameManager manager,Map<String,List<Minel>> minelsSup,Map<Personnage,List<Minel>> minels) {
|
public JPanel genGamePane(Partie partie,GameManager manager,Map<String,List<Minel>> minelsSup,Map<Personnage,List<Minel>> minels) {
|
||||||
|
|
||||||
JPanel globalPan = new JPanel(new BorderLayout());
|
JPanel globalPan = new JPanel(new BorderLayout());
|
||||||
|
|
||||||
//Center Panel
|
//Center Panel
|
||||||
MouseReactiveTabbedPane centerPan = new MouseReactiveTabbedPane(JTabbedPane.TOP);
|
MouseReactiveTabbedPane centerPan = new MouseReactiveTabbedPane(JTabbedPane.TOP);
|
||||||
|
|
||||||
int j = 0;
|
int j = 0;
|
||||||
for(String s : minelsSup.keySet()) {
|
|
||||||
//Calcul des dimensions max
|
|
||||||
int minelCount = minelsSup.get(s).size();
|
|
||||||
int lincount = (int) Math.ceil(((double)minelCount)/((double)Parametres.instance.minielParLigne));
|
|
||||||
ScrollablePanel centralLocalBpanPan = new ScrollablePanel(new GridLayout(lincount,Parametres.instance.minielParLigne,-1,-1));
|
|
||||||
centralLocalBpanPan.setScrollableWidth( ScrollablePanel.ScrollableSizeHint.FIT );
|
|
||||||
minelsSup.get(s).stream()
|
|
||||||
.map(m -> m.genContentPane())
|
|
||||||
.forEach(mpan -> {
|
|
||||||
centralLocalBpanPan.add(mpan);
|
|
||||||
mpan.setBorder(BorderFactory.createLineBorder(ParseUtils.randDarkBlueColor(),3));
|
|
||||||
mpan.setMinimumSize(Parametres.instance.minielMinSize);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
if(lincount > Parametres.instance.lignesDeMinielAvantScroll) {
|
|
||||||
|
|
||||||
JScrollPane jsp = new JScrollPane(centralLocalBpanPan,JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
|
for(String s : minelsSup.keySet()) {
|
||||||
centerPan.insertTab(s,null,jsp,null,j++);
|
JPanel centralLocalBpanPan = new JPanel(new GridLayout(2,(minelsSup.get(s).size()+1)/2,-1,-1));
|
||||||
} else
|
minelsSup.get(s).stream().map(m -> m.genContentPane()).forEach(mpan -> {centralLocalBpanPan.add(mpan);mpan.setBorder(BorderFactory.createLineBorder(ParseUtils.randDarkBlueColor(),2));});
|
||||||
centerPan.insertTab(s,null,centralLocalBpanPan,null,j++);
|
JScrollPane centralLocalPan = new JScrollPane(centralLocalBpanPan);
|
||||||
|
centerPan.insertTab(s,null,centralLocalPan,null,j++);
|
||||||
|
System.out.println(j);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(Personnage p : minels.keySet()) {
|
for(Personnage p : minels.keySet()) {
|
||||||
|
JPanel centralLocalBpanPan = new JPanel(new GridLayout(2, (minels.get(p).size()+1)/2,-1,-1));
|
||||||
//Calcul des dimensions max
|
minels.get(p).stream().map(m -> m.genContentPane()).forEach(mpan -> {centralLocalBpanPan.add(mpan);mpan.setBorder(BorderFactory.createLineBorder(ParseUtils.randDarkBlueColor(),2));});
|
||||||
int minelCount = minels.get(p).size();
|
JScrollPane centralLocalPan = new JScrollPane(centralLocalBpanPan);
|
||||||
int lincount = (int) Math.ceil(((double)minelCount)/((double)Parametres.instance.minielParLigne));
|
centerPan.insertTab(p.getNom(),null,centralLocalPan,null,j++);
|
||||||
ScrollablePanel centralLocalBpanPan = new ScrollablePanel(new GridLayout(lincount,Parametres.instance.minielParLigne,-1,-1));
|
System.out.println(j);
|
||||||
centralLocalBpanPan.setScrollableWidth( ScrollablePanel.ScrollableSizeHint.FIT );
|
|
||||||
minels.get(p).stream()
|
|
||||||
.map(m -> m.genContentPane())
|
|
||||||
.forEach(mpan -> {
|
|
||||||
centralLocalBpanPan.add(mpan);
|
|
||||||
mpan.setBorder(BorderFactory.createLineBorder(ParseUtils.randDarkBlueColor(),3));
|
|
||||||
mpan.setMinimumSize(Parametres.instance.minielMinSize);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
if(lincount > Parametres.instance.lignesDeMinielAvantScroll) {
|
|
||||||
JScrollPane jsp = new JScrollPane(centralLocalBpanPan,JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
|
|
||||||
centerPan.insertTab(p.getNom(),null,jsp,null,j++);
|
|
||||||
} else
|
|
||||||
centerPan.insertTab(p.getNom(),null,centralLocalBpanPan,null,j++);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < centerPan.getTabCount(); i++) {
|
||||||
|
System.out.println(i);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
//Left Panel
|
||||||
|
JPanel leftPan = new JPanel(new GridLayout(minels.size() + minelsSup.size(), 1));
|
||||||
|
|
||||||
|
for(String s : minelsSup.keySet()) {
|
||||||
|
JButton localButton = new JButton(s);
|
||||||
|
localButton.addActionListener(e -> centerLayout.show(centerPan, s));
|
||||||
|
try {
|
||||||
|
localButton.setDropTarget(new NotADropTarget());
|
||||||
|
localButton.getDropTarget().addDropTargetListener(new HoverSelect(centerLayout, centerPan, s));
|
||||||
|
} catch (TooManyListenersException e1) {
|
||||||
|
e1.printStackTrace();
|
||||||
|
}
|
||||||
|
leftPan.add(localButton);
|
||||||
|
}
|
||||||
|
for(Personnage p : minels.keySet()) {
|
||||||
|
JButton localButton = new JButton(p.getNom());
|
||||||
|
localButton.addActionListener(e -> centerLayout.show(centerPan, personnageIdentifier(p)));
|
||||||
|
try {
|
||||||
|
localButton.setDropTarget(new ObjetDropTarget(manager, p, ()->manager.inventoryUpdate(p)));
|
||||||
|
localButton.getDropTarget().addDropTargetListener(new HoverSelect(centerLayout, centerPan, personnageIdentifier(p),DnDConstants.ACTION_MOVE));
|
||||||
|
} catch (TooManyListenersException e1) {
|
||||||
|
e1.printStackTrace();
|
||||||
|
}
|
||||||
|
leftPan.add(localButton);
|
||||||
|
}
|
||||||
|
|
||||||
|
globalPan.add(leftPan, BorderLayout.WEST);
|
||||||
|
*/
|
||||||
globalPan.add(centerPan, BorderLayout.CENTER);
|
globalPan.add(centerPan, BorderLayout.CENTER);
|
||||||
return globalPan;
|
return globalPan;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static final String personnageIdentifier(Personnage personnage) {
|
public String personnageIdentifier(Personnage personnage) {
|
||||||
return String.format("%08X",System.identityHashCode(personnage))+personnage.getNom();
|
return String.format("%08X",System.identityHashCode(personnage))+personnage.getNom();
|
||||||
}
|
}
|
||||||
|
|
||||||
public class WListener extends WindowAdapter{
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void windowClosing(WindowEvent e) {
|
|
||||||
super.windowClosing(e);
|
|
||||||
int res = JOptionPane.showConfirmDialog(MurderatorGameFrame.this,
|
|
||||||
"En fermant cette fenêtre, vous allez mettre fin à la murder et supprimer les sauvegardes automatiques ?",
|
|
||||||
"Fermeture",
|
|
||||||
JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE);
|
|
||||||
|
|
||||||
if(res==JOptionPane.OK_OPTION) {
|
|
||||||
|
|
||||||
manager.removeQuickSaves();
|
|
||||||
MinelsCreator.closeMiniels(minels, minelsSup);
|
|
||||||
|
|
||||||
MurderatorGameFrame.this.setVisible(false);
|
|
||||||
MurderatorGameFrame.this.dispose();
|
|
||||||
|
|
||||||
System.exit(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,23 +1,16 @@
|
|||||||
package com.bernard.murder.view.minel;
|
package com.bernard.murder.view.minel;
|
||||||
|
|
||||||
import java.awt.BorderLayout;
|
import java.awt.BorderLayout;
|
||||||
import java.awt.GridBagConstraints;
|
|
||||||
import java.awt.GridBagLayout;
|
|
||||||
import java.awt.event.MouseAdapter;
|
|
||||||
import java.awt.event.MouseEvent;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import javax.swing.BorderFactory;
|
|
||||||
import javax.swing.BoxLayout;
|
import javax.swing.BoxLayout;
|
||||||
import javax.swing.JButton;
|
import javax.swing.JButton;
|
||||||
import javax.swing.JLabel;
|
import javax.swing.JLabel;
|
||||||
import javax.swing.JMenuItem;
|
|
||||||
import javax.swing.JPanel;
|
import javax.swing.JPanel;
|
||||||
import javax.swing.JPopupMenu;
|
|
||||||
import javax.swing.JScrollPane;
|
import javax.swing.JScrollPane;
|
||||||
import javax.swing.JSeparator;
|
import javax.swing.JSeparator;
|
||||||
import javax.swing.Timer;
|
import javax.swing.Timer;
|
||||||
@ -25,11 +18,10 @@ import javax.swing.Timer;
|
|||||||
import com.amihaiemil.eoyaml.Yaml;
|
import com.amihaiemil.eoyaml.Yaml;
|
||||||
import com.amihaiemil.eoyaml.YamlMapping;
|
import com.amihaiemil.eoyaml.YamlMapping;
|
||||||
import com.amihaiemil.eoyaml.YamlMappingBuilder;
|
import com.amihaiemil.eoyaml.YamlMappingBuilder;
|
||||||
import com.bernard.murder.Parametres;
|
import com.bernard.murder.ParseUtils;
|
||||||
import com.bernard.murder.game.GameManager;
|
import com.bernard.murder.game.GameManager;
|
||||||
import com.bernard.murder.model.Action;
|
import com.bernard.murder.model.Action;
|
||||||
import com.bernard.murder.model.Personnage;
|
import com.bernard.murder.model.Personnage;
|
||||||
import com.bernard.util.ParseUtils;
|
|
||||||
|
|
||||||
public class ActionsMinel extends Minel {
|
public class ActionsMinel extends Minel {
|
||||||
|
|
||||||
@ -41,7 +33,6 @@ public class ActionsMinel extends Minel {
|
|||||||
Collection<Action> updatingActions;
|
Collection<Action> updatingActions;
|
||||||
Map<Action,JLabel> actionStatusTexts = new HashMap<>();
|
Map<Action,JLabel> actionStatusTexts = new HashMap<>();
|
||||||
Map<Action,JButton> actionButtons = new HashMap<>();
|
Map<Action,JButton> actionButtons = new HashMap<>();
|
||||||
Map<Action,JPopupMenu> jpmMenus = new HashMap<>();
|
|
||||||
|
|
||||||
public ActionsMinel(GameManager manager, Personnage perso) {
|
public ActionsMinel(GameManager manager, Personnage perso) {
|
||||||
super(manager);
|
super(manager);
|
||||||
@ -62,33 +53,17 @@ public class ActionsMinel extends Minel {
|
|||||||
actionsListPan.setLayout(new BoxLayout(actionsListPan, BoxLayout.PAGE_AXIS));
|
actionsListPan.setLayout(new BoxLayout(actionsListPan, BoxLayout.PAGE_AXIS));
|
||||||
for(Action a : personnage.getActions()) {
|
for(Action a : personnage.getActions()) {
|
||||||
JPanel actionControlPanel = new JPanel(new BorderLayout());
|
JPanel actionControlPanel = new JPanel(new BorderLayout());
|
||||||
JPanel leftPan = new JPanel(new BorderLayout());
|
|
||||||
JLabel actionName = new JLabel(a.getName());
|
JLabel actionName = new JLabel(a.getName());
|
||||||
|
|
||||||
JPanel outerButton = new JPanel(new GridBagLayout());
|
|
||||||
|
|
||||||
JButton actionButton = new JButton("GO");
|
JButton actionButton = new JButton("GO");
|
||||||
GridBagConstraints gbc = new GridBagConstraints();
|
|
||||||
gbc.fill = GridBagConstraints.NONE;
|
|
||||||
gbc.gridx = 0;
|
|
||||||
gbc.gridy = 0;
|
|
||||||
gbc.anchor = GridBagConstraints.CENTER;
|
|
||||||
outerButton.add(actionButton,gbc);
|
|
||||||
|
|
||||||
JLabel actionStatusText = new JLabel(availableText);
|
JLabel actionStatusText = new JLabel(availableText);
|
||||||
|
|
||||||
actionButton.addActionListener(e->launchAction(a));
|
actionButton.addActionListener(e->launchAction(a));
|
||||||
actionButtons.put(a, actionButton);
|
actionButtons.put(a, actionButton);
|
||||||
actionStatusTexts.put(a, actionStatusText);
|
actionStatusTexts.put(a, actionStatusText);
|
||||||
|
|
||||||
leftPan.add(actionName, BorderLayout.NORTH);
|
actionControlPanel.add(actionButton, BorderLayout.EAST);
|
||||||
leftPan.add(actionStatusText, BorderLayout.SOUTH);
|
actionControlPanel.add(actionName, BorderLayout.NORTH);
|
||||||
actionControlPanel.add(outerButton, BorderLayout.EAST);
|
actionControlPanel.add(actionStatusText, BorderLayout.SOUTH);
|
||||||
actionControlPanel.add(leftPan,BorderLayout.CENTER);
|
|
||||||
|
|
||||||
ActionPopupListener apl = new ActionPopupListener(a);
|
|
||||||
jpmMenus.put(a, apl.makePopup());
|
|
||||||
actionControlPanel.addMouseListener(apl);
|
|
||||||
|
|
||||||
actionsListPan.add(actionControlPanel);
|
actionsListPan.add(actionControlPanel);
|
||||||
actionsListPan.add(new JSeparator());
|
actionsListPan.add(new JSeparator());
|
||||||
@ -96,14 +71,9 @@ public class ActionsMinel extends Minel {
|
|||||||
Timer timer = new Timer(100, e->updateTexts());
|
Timer timer = new Timer(100, e->updateTexts());
|
||||||
timer.start();
|
timer.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
JScrollPane globalScroll = new JScrollPane(actionsListPan);
|
JScrollPane globalScroll = new JScrollPane(actionsListPan);
|
||||||
|
JLabel titleLabel = new JLabel("Actions de "+personnage.getNom());
|
||||||
JLabel titre = new JLabel("Actions de "+personnage.getNom(),JLabel.CENTER);
|
globalPan.add(titleLabel,BorderLayout.NORTH);
|
||||||
titre.setFont(Parametres.instance.minielTitleFont);
|
|
||||||
titre.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
|
|
||||||
|
|
||||||
globalPan.add(titre,BorderLayout.NORTH);
|
|
||||||
globalPan.add(globalScroll,BorderLayout.CENTER);
|
globalPan.add(globalScroll,BorderLayout.CENTER);
|
||||||
|
|
||||||
updateTexts();
|
updateTexts();
|
||||||
@ -113,19 +83,12 @@ public class ActionsMinel extends Minel {
|
|||||||
|
|
||||||
private void launchAction(Action a) {
|
private void launchAction(Action a) {
|
||||||
if(!a.canBeLaunched())return;
|
if(!a.canBeLaunched())return;
|
||||||
manager.launchAction(a);
|
a.launch();
|
||||||
actionButtons.get(a).setEnabled(false);
|
actionButtons.get(a).setEnabled(false);
|
||||||
updateText(a);
|
updateText(a);
|
||||||
updatingActions.add(a);
|
updatingActions.add(a);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void resetAction(Action a) {
|
|
||||||
manager.resetAction(a);
|
|
||||||
actionButtons.get(a).setEnabled(true);
|
|
||||||
updateTexts();
|
|
||||||
updatingActions.remove(a);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public YamlMappingBuilder saveToYaml() {
|
public YamlMappingBuilder saveToYaml() {
|
||||||
return Yaml.createYamlMappingBuilder().add("personnage", personnage.getNom());
|
return Yaml.createYamlMappingBuilder().add("personnage", personnage.getNom());
|
||||||
@ -145,37 +108,6 @@ public class ActionsMinel extends Minel {
|
|||||||
actionStatusTexts.get(a).setText(String.format(waitingTimeText, ParseUtils.dumpTimeLength(a.timeToWaitLeft()), ParseUtils.dumpHourDate(a.dateReset())));
|
actionStatusTexts.get(a).setText(String.format(waitingTimeText, ParseUtils.dumpTimeLength(a.timeToWaitLeft()), ParseUtils.dumpHourDate(a.dateReset())));
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ActionPopupListener extends MouseAdapter {
|
|
||||||
|
|
||||||
Action theAction;
|
|
||||||
|
|
||||||
public ActionPopupListener(Action theAction) {
|
|
||||||
this.theAction = theAction;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final JPopupMenu makePopup() {
|
|
||||||
JPopupMenu popup = new JPopupMenu();
|
|
||||||
|
|
||||||
JMenuItem jmi = new JMenuItem("Réinitialiser");
|
|
||||||
jmi.addActionListener(e -> resetAction(theAction));
|
|
||||||
popup.add(jmi);
|
|
||||||
return popup;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void mousePressed(MouseEvent e) {
|
|
||||||
maybeShowPopup(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void mouseReleased(MouseEvent e) {
|
|
||||||
maybeShowPopup(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void maybeShowPopup(MouseEvent e) {
|
|
||||||
if (e.isPopupTrigger()) {
|
|
||||||
jpmMenus.get(theAction).show(e.getComponent(), e.getX(), e.getY());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,25 +3,16 @@ package com.bernard.murder.view.minel;
|
|||||||
import java.awt.BorderLayout;
|
import java.awt.BorderLayout;
|
||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
import java.awt.Font;
|
import java.awt.Font;
|
||||||
import java.awt.event.MouseAdapter;
|
|
||||||
import java.awt.event.MouseEvent;
|
|
||||||
import java.awt.geom.AffineTransform;
|
|
||||||
|
|
||||||
import javax.swing.BorderFactory;
|
|
||||||
import javax.swing.JButton;
|
import javax.swing.JButton;
|
||||||
import javax.swing.JLabel;
|
import javax.swing.JLabel;
|
||||||
import javax.swing.JList;
|
import javax.swing.JList;
|
||||||
import javax.swing.JMenuItem;
|
|
||||||
import javax.swing.JOptionPane;
|
|
||||||
import javax.swing.JPanel;
|
import javax.swing.JPanel;
|
||||||
import javax.swing.JPopupMenu;
|
|
||||||
import javax.swing.JScrollPane;
|
|
||||||
import javax.swing.ListCellRenderer;
|
import javax.swing.ListCellRenderer;
|
||||||
|
|
||||||
import com.amihaiemil.eoyaml.Yaml;
|
import com.amihaiemil.eoyaml.Yaml;
|
||||||
import com.amihaiemil.eoyaml.YamlMapping;
|
import com.amihaiemil.eoyaml.YamlMapping;
|
||||||
import com.amihaiemil.eoyaml.YamlMappingBuilder;
|
import com.amihaiemil.eoyaml.YamlMappingBuilder;
|
||||||
import com.bernard.murder.Parametres;
|
|
||||||
import com.bernard.murder.game.GameManager;
|
import com.bernard.murder.game.GameManager;
|
||||||
import com.bernard.murder.model.Inventaire;
|
import com.bernard.murder.model.Inventaire;
|
||||||
import com.bernard.murder.model.Objet;
|
import com.bernard.murder.model.Objet;
|
||||||
@ -42,25 +33,19 @@ public class InventaireMinel extends Minel {
|
|||||||
JList<Objet> objets;
|
JList<Objet> objets;
|
||||||
Inventaire inv;
|
Inventaire inv;
|
||||||
|
|
||||||
JPopupMenu invPopup;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JPanel genContentPane() {
|
public JPanel genContentPane() {
|
||||||
JPanel globalpan = new JPanel(new BorderLayout());
|
JPanel globalpan = new JPanel(new BorderLayout());
|
||||||
|
|
||||||
JLabel titre;
|
|
||||||
|
|
||||||
if(inv.getInventoryName()!=null)
|
if(inv.getInventoryName()!=null) {
|
||||||
titre = new JLabel(inv.getInventoryName(),JLabel.CENTER);
|
JLabel invName = new JLabel(inv.getInventoryName());
|
||||||
else
|
globalpan.add(invName, BorderLayout.NORTH);
|
||||||
titre = new JLabel("Inventaire",JLabel.CENTER);
|
}
|
||||||
titre.setFont(Parametres.instance.minielTitleFont);
|
|
||||||
titre.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
|
|
||||||
globalpan.add(titre, BorderLayout.NORTH);
|
|
||||||
|
|
||||||
JPanel inventaire = new JPanel();
|
JPanel inventaire = new JPanel();
|
||||||
|
|
||||||
JButton voler = new JButton("Objet au pif");
|
JButton voler = new JButton("RandomItem");
|
||||||
voler.addActionListener(e -> {
|
voler.addActionListener(e -> {
|
||||||
objets.setSelectedIndex((int) (Math.random() * objets.getModel().getSize()));
|
objets.setSelectedIndex((int) (Math.random() * objets.getModel().getSize()));
|
||||||
});
|
});
|
||||||
@ -69,8 +54,6 @@ public class InventaireMinel extends Minel {
|
|||||||
objets.setCellRenderer(new ObjetListCellRenderer());
|
objets.setCellRenderer(new ObjetListCellRenderer());
|
||||||
objets.setDragEnabled(true);
|
objets.setDragEnabled(true);
|
||||||
objets.setTransferHandler(new ObjetTransferHandler());
|
objets.setTransferHandler(new ObjetTransferHandler());
|
||||||
objets.setOpaque(false);
|
|
||||||
objets.addMouseListener(new InvPopupListener());
|
|
||||||
updateObjets();
|
updateObjets();
|
||||||
final ObjetDropTarget odt = new ObjetDropTarget(manager, inv, this::updateObjets);
|
final ObjetDropTarget odt = new ObjetDropTarget(manager, inv, this::updateObjets);
|
||||||
objets.setDropTarget(odt);
|
objets.setDropTarget(odt);
|
||||||
@ -80,15 +63,15 @@ public class InventaireMinel extends Minel {
|
|||||||
|
|
||||||
inventaire.add(objets);
|
inventaire.add(objets);
|
||||||
|
|
||||||
JScrollPane textsp = new JScrollPane(inventaire);
|
|
||||||
|
|
||||||
globalpan.add(voler, BorderLayout.SOUTH);
|
globalpan.add(voler, BorderLayout.SOUTH);
|
||||||
globalpan.add(textsp, BorderLayout.CENTER);
|
globalpan.add(inventaire, BorderLayout.CENTER);
|
||||||
|
|
||||||
return globalpan;
|
return globalpan;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateObjets() {
|
private void updateObjets() {
|
||||||
|
System.out.print("Updating "+inv+" with");
|
||||||
|
manager.dumpCurrentState();
|
||||||
Objet[] objz = new Objet[inv.getObjects().size()];
|
Objet[] objz = new Objet[inv.getObjects().size()];
|
||||||
objz = inv.getObjects().toArray(objz);
|
objz = inv.getObjects().toArray(objz);
|
||||||
objets.setListData(objz);
|
objets.setListData(objz);
|
||||||
@ -103,21 +86,18 @@ public class InventaireMinel extends Minel {
|
|||||||
|
|
||||||
private static final long serialVersionUID = -7176962839330435585L;
|
private static final long serialVersionUID = -7176962839330435585L;
|
||||||
|
|
||||||
Font origFont = null;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Component getListCellRendererComponent(JList<? extends Objet> list, Objet objet, int index,
|
public Component getListCellRendererComponent(JList<? extends Objet> list, Objet objet, int index,
|
||||||
boolean isSelected, boolean cellHasFocus) {
|
boolean isSelected, boolean cellHasFocus) {
|
||||||
|
|
||||||
setText(objet.getNom());
|
setText(objet.getNom());
|
||||||
if(origFont==null)origFont = getFont();
|
|
||||||
if (isSelected) {
|
if (isSelected) {
|
||||||
double ratio = 0.9;
|
setFont(getFont().deriveFont(Font.BOLD));
|
||||||
setFont(origFont.deriveFont(AffineTransform.getScaleInstance(ratio, 1.0)));
|
|
||||||
setBackground(list.getSelectionBackground());
|
setBackground(list.getSelectionBackground());
|
||||||
setForeground(list.getSelectionForeground());
|
setForeground(list.getSelectionForeground());
|
||||||
} else {
|
} else {
|
||||||
setFont(origFont.deriveFont(Font.PLAIN));
|
setFont(getFont().deriveFont(Font.PLAIN));
|
||||||
setBackground(list.getBackground());
|
setBackground(list.getBackground());
|
||||||
setForeground(list.getForeground());
|
setForeground(list.getForeground());
|
||||||
}
|
}
|
||||||
@ -126,70 +106,4 @@ public class InventaireMinel extends Minel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class InvPopupListener extends MouseAdapter{
|
|
||||||
|
|
||||||
JPopupMenu jpm;
|
|
||||||
JMenuItem renameOpt;
|
|
||||||
JMenuItem deleteOpt;
|
|
||||||
|
|
||||||
public InvPopupListener() {
|
|
||||||
|
|
||||||
jpm = new JPopupMenu();
|
|
||||||
|
|
||||||
JMenuItem createOpt = new JMenuItem("Créer");
|
|
||||||
createOpt.addActionListener(e -> {
|
|
||||||
String newName = JOptionPane.showInputDialog(
|
|
||||||
objets,
|
|
||||||
"Nom du nouvel objet",
|
|
||||||
"Création d'objet",
|
|
||||||
JOptionPane.QUESTION_MESSAGE);
|
|
||||||
if(newName != null)
|
|
||||||
manager.createObjet(newName,inv);
|
|
||||||
});
|
|
||||||
jpm.add(createOpt);
|
|
||||||
renameOpt = new JMenuItem("Renommer");
|
|
||||||
renameOpt.addActionListener(e -> {
|
|
||||||
String newName = JOptionPane.showInputDialog(
|
|
||||||
objets,
|
|
||||||
"Nouveau nom",
|
|
||||||
"Renommage d'objet",
|
|
||||||
JOptionPane.QUESTION_MESSAGE);
|
|
||||||
if(newName != null)
|
|
||||||
manager.renameObjet(objets.getSelectedValue(),newName,inv);
|
|
||||||
});
|
|
||||||
jpm.add(renameOpt);
|
|
||||||
deleteOpt = new JMenuItem("Supprimer");
|
|
||||||
deleteOpt.addActionListener(e -> {
|
|
||||||
int res = JOptionPane.showConfirmDialog(
|
|
||||||
objets,
|
|
||||||
"Voulez-vous vraiment détruire cet objet ?",
|
|
||||||
"Destruction d'objet",
|
|
||||||
JOptionPane.WARNING_MESSAGE,
|
|
||||||
JOptionPane.YES_NO_OPTION);
|
|
||||||
if(res == JOptionPane.OK_OPTION)
|
|
||||||
manager.deleteObjet(objets.getSelectedValue(),inv);
|
|
||||||
});
|
|
||||||
jpm.add(deleteOpt);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void mousePressed(MouseEvent e) {
|
|
||||||
maybeShowPopup(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void mouseReleased(MouseEvent e) {
|
|
||||||
maybeShowPopup(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void maybeShowPopup(MouseEvent e) {
|
|
||||||
if (e.isPopupTrigger()) {
|
|
||||||
objets.setSelectedIndex(objets.locationToIndex(e.getPoint()));
|
|
||||||
renameOpt.setEnabled(!objets.isSelectionEmpty());
|
|
||||||
deleteOpt.setEnabled(!objets.isSelectionEmpty());
|
|
||||||
jpm.show(e.getComponent(), e.getX(), e.getY());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -24,6 +24,4 @@ public abstract class Minel{
|
|||||||
|
|
||||||
public abstract YamlMappingBuilder saveToYaml();
|
public abstract YamlMappingBuilder saveToYaml();
|
||||||
|
|
||||||
public void onFrameClose() {};
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,27 +8,22 @@ import java.util.Set;
|
|||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import javax.swing.BorderFactory;
|
|
||||||
import javax.swing.JLabel;
|
|
||||||
import javax.swing.JList;
|
import javax.swing.JList;
|
||||||
import javax.swing.JPanel;
|
import javax.swing.JPanel;
|
||||||
import javax.swing.JScrollPane;
|
|
||||||
import javax.swing.JTextField;
|
import javax.swing.JTextField;
|
||||||
import javax.swing.event.DocumentEvent;
|
import javax.swing.event.DocumentEvent;
|
||||||
import javax.swing.event.DocumentListener;
|
|
||||||
|
|
||||||
import com.amihaiemil.eoyaml.Scalar;
|
import com.amihaiemil.eoyaml.Scalar;
|
||||||
import com.amihaiemil.eoyaml.Yaml;
|
import com.amihaiemil.eoyaml.Yaml;
|
||||||
import com.amihaiemil.eoyaml.YamlMapping;
|
import com.amihaiemil.eoyaml.YamlMapping;
|
||||||
import com.amihaiemil.eoyaml.YamlMappingBuilder;
|
import com.amihaiemil.eoyaml.YamlMappingBuilder;
|
||||||
import com.amihaiemil.eoyaml.YamlNode;
|
import com.amihaiemil.eoyaml.YamlNode;
|
||||||
import com.bernard.murder.Parametres;
|
import com.bernard.murder.ParseUtils;
|
||||||
|
import com.bernard.murder.YamlUtils;
|
||||||
import com.bernard.murder.game.GameManager;
|
import com.bernard.murder.game.GameManager;
|
||||||
import com.bernard.murder.model.Inventaire;
|
import com.bernard.murder.model.Inventaire;
|
||||||
import com.bernard.murder.model.Objet;
|
import com.bernard.murder.model.Objet;
|
||||||
import com.bernard.murder.util.view.SimpleDocumentListener;
|
import com.bernard.murder.util.view.SimpleDocumentListener;
|
||||||
import com.bernard.util.ParseUtils;
|
|
||||||
import com.bernard.util.YamlUtils;
|
|
||||||
|
|
||||||
public class ObjetSearchMinel extends Minel {
|
public class ObjetSearchMinel extends Minel {
|
||||||
|
|
||||||
@ -64,32 +59,29 @@ public class ObjetSearchMinel extends Minel {
|
|||||||
|
|
||||||
JPanel globalPan = new JPanel(new BorderLayout());
|
JPanel globalPan = new JPanel(new BorderLayout());
|
||||||
|
|
||||||
JLabel titre = new JLabel("Recherche d'objets",JLabel.CENTER);
|
|
||||||
titre.setFont(Parametres.instance.minielTitleFont);
|
|
||||||
|
|
||||||
JPanel panel = new JPanel(new BorderLayout());
|
|
||||||
panel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
|
|
||||||
JTextField searchField = new JTextField();
|
JTextField searchField = new JTextField();
|
||||||
searchField.setToolTipText("Objet à chercher");
|
searchField.setToolTipText("Objet à chercher");
|
||||||
|
|
||||||
JList<InventorizedObject> searchResults = new JList<>();
|
JList<InventorizedObject> searchResults = new JList<>();
|
||||||
searchResults.setOpaque(false);
|
|
||||||
searchResults.setBorder(BorderFactory.createEmptyBorder(5,2,2,2));
|
|
||||||
|
|
||||||
DocumentListener dl = new SimpleDocumentListener() {
|
|
||||||
|
|
||||||
|
searchField.getDocument().addDocumentListener(new SimpleDocumentListener() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void changedUpdate(DocumentEvent e) {
|
public void changedUpdate(DocumentEvent e) {
|
||||||
|
System.out.println("Updated to "+e.getDocument().toString());
|
||||||
String searchText = searchField.getText();
|
String searchText = searchField.getText();
|
||||||
/*if(searchText.isBlank()) {
|
if(searchText.isBlank()) {
|
||||||
searchResults.setListData(new InventorizedObject[0]);
|
searchResults.setListData(new InventorizedObject[0]);
|
||||||
return;
|
return;
|
||||||
}*/
|
}
|
||||||
Set<InventorizedObject> startMatch = new HashSet<>();
|
Set<InventorizedObject> startMatch = new HashSet<>();
|
||||||
Set<InventorizedObject> anyMatch = new HashSet<>();
|
Set<InventorizedObject> anyMatch = new HashSet<>();
|
||||||
Set<InventorizedObject> subwordMatch = new HashSet<>();
|
Set<InventorizedObject> subwordMatch = new HashSet<>();
|
||||||
|
|
||||||
for(Objet o : objets.keySet()) {
|
for(Objet o : objets.keySet()) {
|
||||||
|
System.out.println(o+"->"+searchText);
|
||||||
if(o.getNom().startsWith(searchText))
|
if(o.getNom().startsWith(searchText))
|
||||||
startMatch.add(new InventorizedObject(o,objets.get(o)));
|
startMatch.add(new InventorizedObject(o,objets.get(o)));
|
||||||
else if(o.getNom().contains(searchText))
|
else if(o.getNom().contains(searchText))
|
||||||
@ -107,18 +99,11 @@ public class ObjetSearchMinel extends Minel {
|
|||||||
searchResults.setListData(results);
|
searchResults.setListData(results);
|
||||||
|
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
searchField.getDocument().addDocumentListener(dl);
|
|
||||||
|
|
||||||
//Remplis la liste pour la première fois
|
globalPan.add(searchField, BorderLayout.NORTH);
|
||||||
dl.changedUpdate(null);
|
globalPan.add(searchResults,BorderLayout.CENTER);
|
||||||
|
|
||||||
|
|
||||||
panel.add(searchField, BorderLayout.NORTH);
|
|
||||||
panel.add(new JScrollPane(searchResults),BorderLayout.CENTER);
|
|
||||||
|
|
||||||
globalPan.add(titre,BorderLayout.NORTH);
|
|
||||||
globalPan.add(panel,BorderLayout.CENTER);
|
|
||||||
return globalPan;
|
return globalPan;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,27 +1,11 @@
|
|||||||
package com.bernard.murder.view.minel;
|
package com.bernard.murder.view.minel;
|
||||||
|
|
||||||
import java.awt.BorderLayout;
|
|
||||||
import java.awt.Font;
|
|
||||||
import java.awt.GridLayout;
|
|
||||||
import java.awt.event.MouseAdapter;
|
|
||||||
import java.awt.event.MouseEvent;
|
|
||||||
import java.net.SocketException;
|
|
||||||
import java.net.UnknownHostException;
|
|
||||||
import java.util.Vector;
|
|
||||||
|
|
||||||
import javax.swing.BorderFactory;
|
|
||||||
import javax.swing.JLabel;
|
import javax.swing.JLabel;
|
||||||
import javax.swing.JList;
|
|
||||||
import javax.swing.JMenuItem;
|
|
||||||
import javax.swing.JOptionPane;
|
|
||||||
import javax.swing.JPanel;
|
import javax.swing.JPanel;
|
||||||
import javax.swing.JPopupMenu;
|
|
||||||
import javax.swing.JScrollPane;
|
|
||||||
|
|
||||||
import com.amihaiemil.eoyaml.Yaml;
|
import com.amihaiemil.eoyaml.Yaml;
|
||||||
import com.amihaiemil.eoyaml.YamlMapping;
|
import com.amihaiemil.eoyaml.YamlMapping;
|
||||||
import com.amihaiemil.eoyaml.YamlMappingBuilder;
|
import com.amihaiemil.eoyaml.YamlMappingBuilder;
|
||||||
import com.bernard.murder.Parametres;
|
|
||||||
import com.bernard.murder.audio.AudioServer;
|
import com.bernard.murder.audio.AudioServer;
|
||||||
import com.bernard.murder.game.GameManager;
|
import com.bernard.murder.game.GameManager;
|
||||||
|
|
||||||
@ -29,159 +13,27 @@ public class ServeurMinel extends Minel {
|
|||||||
|
|
||||||
AudioServer serveur;
|
AudioServer serveur;
|
||||||
|
|
||||||
JList<Integer> micListe;
|
|
||||||
JList<Integer> spkListe;
|
|
||||||
|
|
||||||
JPopupMenu micPopup;
|
|
||||||
JPopupMenu spkPopup;
|
|
||||||
|
|
||||||
public ServeurMinel(GameManager manager) {
|
public ServeurMinel(GameManager manager) {
|
||||||
super(manager);
|
super(manager);
|
||||||
try {
|
serveur = new AudioServer();
|
||||||
serveur = new AudioServer(manager);
|
|
||||||
serveur.genPasswords();
|
|
||||||
}catch(SocketException | UnknownHostException ex) {
|
|
||||||
JOptionPane.showMessageDialog(null, "Lancement du serveur audio impossible !\n"+ex.getMessage(), "Impossible de lancer le serveur audio", JOptionPane.ERROR_MESSAGE, null);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ServeurMinel(GameManager manager,YamlMapping ym) {
|
public ServeurMinel(GameManager manager,YamlMapping ym) {
|
||||||
this(manager);
|
super(manager);
|
||||||
// On se fiche de la sauvegarde automatique.
|
serveur = new AudioServer();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JPanel genContentPane() {
|
public JPanel genContentPane() {
|
||||||
JPanel panel = new JPanel(new BorderLayout());
|
JPanel pan = new JPanel();
|
||||||
|
JLabel label = new JLabel("Rien pour l'instant");
|
||||||
JLabel titre = new JLabel("Status du serveur",JLabel.CENTER);
|
pan.add(label);
|
||||||
titre.setFont(Parametres.instance.minielTitleFont);
|
return pan;
|
||||||
titre.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
|
|
||||||
|
|
||||||
micListe = new JList<>();
|
|
||||||
micListe.setOpaque(false);
|
|
||||||
spkListe = new JList<>();
|
|
||||||
spkListe.setOpaque(false);
|
|
||||||
|
|
||||||
EnceintePopupListener epl = new EnceintePopupListener();
|
|
||||||
spkPopup = epl.makePopup();
|
|
||||||
spkListe.addMouseListener(epl);
|
|
||||||
|
|
||||||
MicsPopupListener mpl = new MicsPopupListener();
|
|
||||||
micPopup = mpl.makePopup();
|
|
||||||
micListe.addMouseListener(mpl);
|
|
||||||
|
|
||||||
serveur.addChangeListener(() -> {
|
|
||||||
// Updating lists content
|
|
||||||
micListe.setListData(new Vector<Integer>(serveur.getMics().keySet()));
|
|
||||||
spkListe.setListData(new Vector<Integer>(serveur.getSpeakers().keySet()));
|
|
||||||
});
|
|
||||||
|
|
||||||
JScrollPane jE = new JScrollPane(spkListe);
|
|
||||||
jE.setBorder(BorderFactory.createTitledBorder("Enceintes connéctées"));
|
|
||||||
JScrollPane jM = new JScrollPane(micListe);
|
|
||||||
jM.setBorder(BorderFactory.createTitledBorder("Microphones connéctés"));
|
|
||||||
|
|
||||||
JPanel centerP = new JPanel(new GridLayout(2, 1));
|
|
||||||
|
|
||||||
centerP.add(jE);
|
|
||||||
centerP.add(jM);
|
|
||||||
|
|
||||||
panel.add(titre,BorderLayout.NORTH);
|
|
||||||
panel.add(centerP,BorderLayout.CENTER);
|
|
||||||
|
|
||||||
return panel;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class EnceintePopupListener extends MouseAdapter{
|
|
||||||
|
|
||||||
public final JPopupMenu makePopup() {
|
|
||||||
JPopupMenu popup = new JPopupMenu();
|
|
||||||
|
|
||||||
JLabel idText = new JLabel();
|
|
||||||
idText.setFont(idText.getFont().deriveFont(Font.ITALIC));
|
|
||||||
idText.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
|
|
||||||
spkListe.getSelectionModel().addListSelectionListener(e ->
|
|
||||||
idText.setText("Id: "+ (spkListe.getSelectedValue()!=null?spkListe.getSelectedValue():-1))
|
|
||||||
);
|
|
||||||
popup.add(idText);
|
|
||||||
JMenuItem jmi = new JMenuItem("Silence");
|
|
||||||
jmi.addActionListener(e -> {
|
|
||||||
serveur.forceSilence(spkListe.getSelectedValue());
|
|
||||||
});
|
|
||||||
popup.add(jmi);
|
|
||||||
jmi = new JMenuItem("Déconnecter");
|
|
||||||
jmi.addActionListener(e -> {
|
|
||||||
serveur.disconnectEnceinte(spkListe.getSelectedValue());
|
|
||||||
});
|
|
||||||
popup.add(jmi);
|
|
||||||
return popup;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void mousePressed(MouseEvent e) {
|
|
||||||
maybeShowPopup(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void mouseReleased(MouseEvent e) {
|
|
||||||
maybeShowPopup(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void maybeShowPopup(MouseEvent e) {
|
|
||||||
if (e.isPopupTrigger()) {
|
|
||||||
spkListe.setSelectedIndex(spkListe.locationToIndex(e.getPoint()));
|
|
||||||
if(!spkListe.isSelectionEmpty())
|
|
||||||
spkPopup.show(e.getComponent(), e.getX(), e.getY());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class MicsPopupListener extends MouseAdapter{
|
|
||||||
|
|
||||||
public final JPopupMenu makePopup() {
|
|
||||||
JPopupMenu popup = new JPopupMenu();
|
|
||||||
|
|
||||||
JLabel idText = new JLabel();
|
|
||||||
idText.setFont(idText.getFont().deriveFont(Font.ITALIC));
|
|
||||||
idText.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
|
|
||||||
micListe.getSelectionModel().addListSelectionListener(e -> //XXX: Tester si l'affichage se met bien à jour ici
|
|
||||||
idText.setText("Id: "+ (micListe.getSelectedValue()!=null?micListe.getSelectedValue():-1))
|
|
||||||
);
|
|
||||||
popup.add(idText);
|
|
||||||
JMenuItem jmi = new JMenuItem("Déconnecter");
|
|
||||||
jmi.addActionListener(e -> {
|
|
||||||
serveur.disconnectMic(micListe.getSelectedValue());
|
|
||||||
});
|
|
||||||
popup.add(jmi);
|
|
||||||
return popup;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void mousePressed(MouseEvent e) {
|
|
||||||
maybeShowPopup(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void mouseReleased(MouseEvent e) {
|
|
||||||
maybeShowPopup(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void maybeShowPopup(MouseEvent e) {
|
|
||||||
if (e.isPopupTrigger()) {
|
|
||||||
micListe.setSelectedIndex(micListe.locationToIndex(e.getPoint()));
|
|
||||||
if(!micListe.isSelectionEmpty())
|
|
||||||
micPopup.show(e.getComponent(), e.getX(), e.getY());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public YamlMappingBuilder saveToYaml() {
|
public YamlMappingBuilder saveToYaml() {
|
||||||
// Ce miniel représente le serveur audio, indépendant du relancement
|
|
||||||
return Yaml.createYamlMappingBuilder();
|
return Yaml.createYamlMappingBuilder();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFrameClose() {
|
|
||||||
serveur.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
29
src/main/java/com/bernard/murder/view/minel/StatusMinel.java
Executable file
29
src/main/java/com/bernard/murder/view/minel/StatusMinel.java
Executable file
@ -0,0 +1,29 @@
|
|||||||
|
package com.bernard.murder.view.minel;
|
||||||
|
|
||||||
|
import javax.swing.JPanel;
|
||||||
|
|
||||||
|
import com.amihaiemil.eoyaml.Yaml;
|
||||||
|
import com.amihaiemil.eoyaml.YamlMappingBuilder;
|
||||||
|
import com.bernard.murder.game.GameManager;
|
||||||
|
import com.bernard.murder.model.Personnage;
|
||||||
|
|
||||||
|
public class StatusMinel extends Minel {
|
||||||
|
|
||||||
|
public StatusMinel(GameManager manager, Personnage personnage) {
|
||||||
|
super(manager);
|
||||||
|
// TODO Auto-generated constructor stub
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JPanel genContentPane() {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public YamlMappingBuilder saveToYaml() {
|
||||||
|
//TODO auto-generated thingy
|
||||||
|
return Yaml.createYamlMappingBuilder();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -2,8 +2,6 @@ package com.bernard.murder.view.minel;
|
|||||||
|
|
||||||
import java.awt.BorderLayout;
|
import java.awt.BorderLayout;
|
||||||
|
|
||||||
import javax.swing.BorderFactory;
|
|
||||||
import javax.swing.JLabel;
|
|
||||||
import javax.swing.JPanel;
|
import javax.swing.JPanel;
|
||||||
import javax.swing.JScrollPane;
|
import javax.swing.JScrollPane;
|
||||||
import javax.swing.JTextArea;
|
import javax.swing.JTextArea;
|
||||||
@ -12,11 +10,11 @@ import javax.swing.border.EmptyBorder;
|
|||||||
import com.amihaiemil.eoyaml.Yaml;
|
import com.amihaiemil.eoyaml.Yaml;
|
||||||
import com.amihaiemil.eoyaml.YamlMapping;
|
import com.amihaiemil.eoyaml.YamlMapping;
|
||||||
import com.amihaiemil.eoyaml.YamlMappingBuilder;
|
import com.amihaiemil.eoyaml.YamlMappingBuilder;
|
||||||
import com.bernard.murder.Parametres;
|
|
||||||
import com.bernard.murder.game.GameManager;
|
import com.bernard.murder.game.GameManager;
|
||||||
|
|
||||||
public class TextPanMinel extends Minel {
|
public class TextPanMinel extends Minel {
|
||||||
|
|
||||||
|
String initTexte = "";
|
||||||
JTextArea textArea;
|
JTextArea textArea;
|
||||||
|
|
||||||
public TextPanMinel(GameManager manager) {
|
public TextPanMinel(GameManager manager) {
|
||||||
@ -24,35 +22,29 @@ public class TextPanMinel extends Minel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public TextPanMinel(GameManager gm, YamlMapping ym) {
|
public TextPanMinel(GameManager gm, YamlMapping ym) {
|
||||||
this(gm);
|
super(gm);
|
||||||
textArea.setText(ym.string("texte"));
|
initTexte = ym.string("texte");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JPanel genContentPane() {
|
public JPanel genContentPane() {
|
||||||
JPanel globalPan = new JPanel(new BorderLayout());
|
JPanel globalPan = new JPanel(new BorderLayout());
|
||||||
|
//globalPan.setBackground(ParseUtils.randColor());
|
||||||
JLabel titre = new JLabel("Notes",JLabel.CENTER);
|
|
||||||
titre.setFont(Parametres.instance.minielTitleFont);
|
|
||||||
titre.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
|
|
||||||
|
|
||||||
|
|
||||||
textArea = new JTextArea();
|
textArea = new JTextArea();
|
||||||
textArea.setBorder(new EmptyBorder(23,23,23,23));
|
textArea.setBorder(new EmptyBorder(23,23,23,23));
|
||||||
textArea.setText("");
|
textArea.setText(initTexte);
|
||||||
textArea.setLineWrap(true);
|
|
||||||
|
|
||||||
textArea.setBackground(Parametres.instance.textPanMinielBackgroundColor);
|
//Color col = ParseUtils.randColor();
|
||||||
textArea.setForeground(Parametres.instance.textPanMinielTextColor);
|
//textArea.setBackground(col);
|
||||||
|
//textArea.setForeground(ParseUtils.getContrastColor(col));
|
||||||
|
|
||||||
globalPan.add(titre,BorderLayout.NORTH);
|
|
||||||
globalPan.add(new JScrollPane(textArea),BorderLayout.CENTER);
|
globalPan.add(new JScrollPane(textArea),BorderLayout.CENTER);
|
||||||
return globalPan;
|
return globalPan;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public YamlMappingBuilder saveToYaml() {
|
public YamlMappingBuilder saveToYaml() {
|
||||||
return Yaml.createYamlMappingBuilder().add("texte", textArea!=null?textArea.getText():"");
|
return Yaml.createYamlMappingBuilder().add("texte", textArea!=null?textArea.getText():initTexte);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -36,6 +36,7 @@ public class ObjetDropTarget extends DropTarget {
|
|||||||
}
|
}
|
||||||
for(Runnable runnable : toUpdate)
|
for(Runnable runnable : toUpdate)
|
||||||
runnable.run();
|
runnable.run();
|
||||||
|
manager.dumpCurrentState();
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,7 +5,8 @@ actions:
|
|||||||
status:
|
status:
|
||||||
- Mort
|
- Mort
|
||||||
- Paralysie
|
- Paralysie
|
||||||
- NoKill
|
- NoKill:
|
||||||
|
onStart: true
|
||||||
|
|
||||||
inventaire:
|
inventaire:
|
||||||
# Tout le monde en a un au départ, sera nommé Portefeuille_Bernard, Portefeuille_Jach
|
# Tout le monde en a un au départ, sera nommé Portefeuille_Bernard, Portefeuille_Jach
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user