Ajout de plein de nouveaux miniels (les objets). Ajout du code du serveur aussi

This commit is contained in:
Mysaa 2021-05-26 22:13:07 +02:00
parent 3897fafc01
commit 623d5c307c
40 changed files with 2762 additions and 310 deletions

3
.gitignore vendored
View File

@ -13,3 +13,6 @@ bin/
.classpath
.settings
.project
*.bernard.quickmurder
*.log

View File

@ -6,10 +6,8 @@
* User Manual available at https://docs.gradle.org/6.0/userguide/java_library_plugin.html
*/
plugins {
// Apply the java-library plugin to add support for Java Library
id 'java-library'
}
apply plugin: 'java'
apply plugin: 'eclipse'
repositories {
// Use jcenter for resolving dependencies.
@ -18,16 +16,20 @@ repositories {
mavenCentral()
}
jar {
manifest {
attributes(
'Main-Class': 'com.bernard.murder.view.LauncherFrame'
)
}
from {
configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
}
}
dependencies {
compile 'com.amihaiemil.web:eo-yaml:4.3.3'
implementation 'com.amihaiemil.web:eo-yaml:5.1.3'
implementation 'com.formdev:flatlaf:0.37'
// This dependency is exported to consumers, that is to say found on their compile classpath.
api 'org.apache.commons:commons-math3:3.6.1'
// This dependency is used internally, and not exposed to consumers on their own compile classpath.
implementation 'com.google.guava:guava:28.0-jre'
// Use JUnit test framework
testImplementation 'junit:junit:4.12'
}

View 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);
}
}

View File

@ -1,21 +0,0 @@
package com.bernard.murder;
import com.bernard.murder.view.MurderatorMainFrame;
public class Murderator {
static MurderatorMainFrame mainFrame;
public static void main(String[] args) {
mainFrame = new MurderatorMainFrame();
/*File f = new File("/home/mysaa/Documents/eclipse-workspace/Murderator/uneMurder.bernard.tmurder");
try {
System.out.println(GameCreator.genFromFile(f));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}*/
mainFrame.startFrame();
}
}

View File

@ -2,6 +2,10 @@ 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;
@ -15,11 +19,14 @@ 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) {
@ -28,36 +35,56 @@ public class ParseUtils {
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;
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 Set<String> mappingKeys(YamlMapping mapping) throws IOException{
return mapping.keys().stream().map(n ->{
try {
return Yaml.createYamlInput(n.toString()).readYamlSequence().string(0);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}).collect(Collectors.toSet());
}
public static Stream<YamlNode> sequenceStream(YamlSequence sequence){
return StreamSupport.stream(Spliterators.spliteratorUnknownSize(sequence.iterator(),Spliterator.ORDERED),false);
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 String node(YamlNode n){
try {
return Yaml.createYamlInput(n.toString()).readYamlSequence().string(0);
} catch (IOException e) {
e.printStackTrace();
}
return null;
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){
@ -67,8 +94,54 @@ public class ParseUtils {
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();
}
}

View 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;
}
}
}

View File

@ -0,0 +1,182 @@
package com.bernard.murder.audio;
import java.io.IOException;
import java.net.SocketAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.UUID;
import javax.sound.sampled.AudioFormat;
import com.bernard.murder.BytesUtils;
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 int packetMaxSize = 97282;
public static int communicationPort = 35295;
public Serveur serveur;
int micId = 0;
int speakerId = 0;
Map<Integer,String> mics;
Map<Integer,String> speakers;
Map<Integer,SocketAddress> micsAddr;
Map<Integer,SocketAddress> speakersAddr;
Map<Integer,List<Integer>> listening; // micId, List<speakerId>
public AudioServer() {
mics = new HashMap<Integer, String>();
micsAddr = new HashMap<Integer, SocketAddress>();
speakers = new HashMap<Integer, String>();
speakersAddr = new HashMap<Integer, SocketAddress>();
listening = new HashMap<Integer, List<Integer>>();
try {
initServer();
} catch (SocketException | UnknownHostException e) {
e.printStackTrace();
}
}
public void initServer() throws SocketException, UnknownHostException {
serveur = new Serveur(this::receiveCommand, AudioServer.communicationPort);
}
public void receiveCommand(ByteBuffer data,SocketAddress senderAddress) {
byte commande = data.get();
System.out.println("Commande reçue : "+commande);
switch (commande) {
case AudioServer.DECLARE_NUMBER:
UUID uuid = new UUID(data.getLong(), data.getLong());
byte deviceType = data.get();
String deviceName = BytesUtils.readString(data);
int newId;
switch (deviceType) {
case AudioServer.MIC_DEVICE:
newId = micId++;
mics.put(newId, deviceName);
micsAddr.put(newId, senderAddress);
listening.put(newId, new ArrayList<>());
break;
case AudioServer.SPEAKER_DEVICE:
newId = speakerId++;
speakers.put(newId, deviceName);
speakersAddr.put(newId, senderAddress);
break;
default:return;
}
ByteBuffer out = ByteBuffer.allocate(AudioServer.packetMaxSize);
out.put(AudioServer.OK_ID);
out.putLong(uuid.getMostSignificantBits());
out.putLong(uuid.getLeastSignificantBits());
out.put(deviceType);
out.putInt(newId);
try {
serveur.sendData(out, senderAddress);
} catch (IOException e1) {
e1.printStackTrace();
}
break;
case AudioServer.ASK_STREAMING:
int listened = data.getInt();
int listener = data.getInt();
listening.get(listened).add(listener);
ByteBuffer out3 = ByteBuffer.allocate(AudioServer.packetMaxSize);
out3.put(AudioServer.START_STREAMING);
out3.putInt(listened);
try {
serveur.sendData(out3, micsAddr.get(listened));
} catch (IOException e2) {
e2.printStackTrace();
}
break;
case AudioServer.STOP_STREAMING:
int listened2 = data.getInt();
int listener2 = data.getInt();
listening.get(listener2).remove(listened2);
ByteBuffer out4 = ByteBuffer.allocate(AudioServer.packetMaxSize);
out4.put(AudioServer.STOP_STREAMING);
out4.putInt(listened2);
try {
serveur.sendData(out4, micsAddr.get(listened2));
} catch (IOException e2) {
e2.printStackTrace();
}
break;
case AudioServer.AUDIO_STREAM:
int micId = data.getInt();
byte[] audioData = new byte[data.remaining()];
data.get(audioData);
for(int spck : listening.get(micId)) {
data.clear();
SocketAddress dest = speakersAddr.get(spck);
try {
serveur.sendData(data, dest);
} catch (IOException e1) {
e1.printStackTrace();
}
}
break;
case AudioServer.ASK_AUDIO_LIST:
ByteBuffer out2 = ByteBuffer.allocate(AudioServer.packetMaxSize);
out2.put(AudioServer.GIVE_AUDIO_LIST);
out2.putInt(mics.size());
for(Entry<Integer, String> e : mics.entrySet()) {
out2.putInt(e.getKey());
BytesUtils.writeString(out2, e.getValue());
}
try {
serveur.sendData(out2, senderAddress);
} catch (IOException e1) {
e1.printStackTrace();
}
break;
default:
break;
}
}
}

View File

@ -0,0 +1,150 @@
package com.bernard.murder.audio;
import java.io.IOException;
import java.net.SocketAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.util.UUID;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.TargetDataLine;
import com.bernard.murder.BytesUtils;
public class MicServer {
TargetDataLine micLine;
int packetLength = 9728;
int micId;
String micName;
UUID askedUUID;
Serveur serveur;
SocketAddress masterAddress;
Thread streamingThread;
volatile boolean shouldStream = false;
Runnable serverAnswered;
public MicServer(SocketAddress adresse,String micName,TargetDataLine tdl) {
this.micName = micName;
this.masterAddress = adresse;
this.micLine = tdl;
try {
initServer();
initializeAudioId();
} catch (SocketException | UnknownHostException e) {
e.printStackTrace();
}
}
public void initializeMicDevice() throws LineUnavailableException {
micLine.open(AudioServer.formatAudio);
packetLength = micLine.getBufferSize()/5;
}
public void initServer() throws SocketException, UnknownHostException {
serveur = new Serveur(this::receiveCommand, AudioServer.communicationPort);
}
public void initializeAudioId() {
ByteBuffer buffer = ByteBuffer.allocate(AudioServer.packetMaxSize);
askedUUID = UUID.randomUUID();
buffer.put(AudioServer.DECLARE_NUMBER);
buffer.putLong(askedUUID.getMostSignificantBits());
buffer.putLong(askedUUID.getLeastSignificantBits());
buffer.put(AudioServer.MIC_DEVICE);
BytesUtils.writeString(buffer, micName);
try {
serveur.sendData(buffer,masterAddress);
} catch (IOException e) {
e.printStackTrace();
}
}
public void receiveCommand(ByteBuffer data) {
byte commande = data.get();
switch (commande) {
case AudioServer.START_STREAMING:
int micId = data.getInt();
if(micId != this.micId)return;
shouldStream = true;
launchDataStream();
break;
case AudioServer.STOP_STREAMING:
int micId2 = data.getInt();
if(micId2 != this.micId)return;
shouldStream = false;
break;
case AudioServer.OK_ID:
UUID uuid = new UUID(data.getLong(), data.getLong());
byte deviceType = data.get();
int deviceId = data.getInt();
if(!askedUUID.equals(uuid) || deviceType!=AudioServer.MIC_DEVICE)
return;
micId = deviceId;
serverAnswered.run();
if(micLine==null)
try {
initializeMicDevice();
} catch (LineUnavailableException e) {
e.printStackTrace();
}
break;
default:
break;
}
}
public void launchDataStream() {
if(streamingThread!=null)return;
streamingThread = new Thread(()->{
byte[] packetData = new byte[1+4+packetLength];
ByteBuffer audioPacket = ByteBuffer.wrap(packetData);
audioPacket.put(AudioServer.AUDIO_STREAM);
audioPacket.putInt(micId);
while(shouldStream) {
micLine.read(packetData, 5, packetLength);
try {
serveur.sendData(audioPacket,masterAddress);
} catch (IOException e) {
e.printStackTrace();
}
}
});
streamingThread.start();
}
public void dispose() {
micLine.close();
serveur.dispose();
}
public void setServerAnswered(Runnable serverAnswered) {
this.serverAnswered = serverAnswered;
}
}

View File

@ -0,0 +1,158 @@
package com.bernard.murder.audio;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import com.bernard.murder.ParseUtils;
public class Serveur {
int packetMaxLength = 9600;
// (commande 1, uuid 16, short sliceCount 4, short sliceId 4, int totalSize 8, int offset 8, data ~)
byte dataMergeCommand = (byte) 0xFF;
DatagramSocket socket;
Thread packetReceiver;
Map<UUID, byte[]> byteArrays = new HashMap<>();
Map<UUID, boolean[]> receivedSlicesArray = new HashMap<>();
volatile boolean isReceiving = false;
BiConsumer<ByteBuffer,SocketAddress> consumer;
public Serveur(Consumer<ByteBuffer> dataEater, int port) throws UnknownHostException, SocketException {
this((b,i)->dataEater.accept(b),new InetSocketAddress(port));
}
public Serveur(Consumer<ByteBuffer> dataEater,SocketAddress addresse) throws UnknownHostException, SocketException {
this((b,i)->dataEater.accept(b),addresse);
}
public Serveur(BiConsumer<ByteBuffer,SocketAddress> dataEater,int port) throws UnknownHostException, SocketException {
this(dataEater,new InetSocketAddress(port));
}
public Serveur(BiConsumer<ByteBuffer,SocketAddress> dataEater,SocketAddress adresse) throws SocketException {
byteArrays = new HashMap<UUID, byte[]>();
receivedSlicesArray = new HashMap<UUID, boolean[]>();
this.consumer = dataEater;
this.socket = new DatagramSocket(adresse);
packetReceiver = new Thread(new Runnable() {
@Override
public void run() {
while(isReceiving) {
byte[] data = new byte[packetMaxLength];
DatagramPacket paquet = new DatagramPacket(data, packetMaxLength);
try {
try {
socket.receive(paquet);
}catch(SocketException e) {
return;//probably socket closed
}
if(data[paquet.getOffset()]==0xFF) {
ByteBuffer bb = ByteBuffer.wrap(data, paquet.getOffset() + 1, 41);
UUID uuid = new UUID(bb.getLong(), bb.getLong());
short sliceCount = bb.getShort();
short sliceId = bb.getShort();
int totalSize = bb.getInt();
int offset = bb.getInt();
if(!receivedSlicesArray.containsKey(uuid)) {
byte[] bigData = new byte[totalSize];
boolean[] recievedArray = new boolean[sliceCount];
byteArrays.put(uuid, bigData);
receivedSlicesArray.put(uuid, recievedArray);
}
byte[] bigData = byteArrays.get(uuid);
boolean[] recievedArray = receivedSlicesArray.get(uuid);
System.arraycopy(data, paquet.getOffset()+41, bigData, offset, paquet.getLength()-41);
recievedArray[sliceId] = true;
if(!ParseUtils.and(recievedArray)) {
ByteBuffer dataBuffer = ByteBuffer.wrap(bigData);
consumer.accept(dataBuffer,paquet.getSocketAddress());
byteArrays.remove(uuid);
receivedSlicesArray.remove(uuid);
}
}else {
ByteBuffer dataBuffer = ByteBuffer.wrap(data,paquet.getOffset(),paquet.getLength());
consumer.accept(dataBuffer,paquet.getSocketAddress());
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
});
isReceiving = true;
packetReceiver.start();
}
public void sendData(ByteBuffer buffer,SocketAddress address) throws IOException {
byte[] data = new byte[buffer.position()];
buffer.clear();
buffer.get(data);
sendData(data,address);
}
public void sendData(byte[] data, SocketAddress address) throws IOException {
if(data.length < packetMaxLength) {
DatagramPacket packet = new DatagramPacket(data, data.length,address);
socket.send(packet);
}else {
short packetCount = (short) (data.length / (packetMaxLength-42));
short packetLength = (short) (data.length / packetCount);
short lastPacketLength = (short) (data.length - (packetCount-1)*packetLength);
UUID uuid = UUID.randomUUID();
byte[][] dataz = new byte[packetCount][];
for (short i = 0; i < dataz.length-1; i++) {
byte[] packagePayload = new byte[packetLength+41];
ByteBuffer buffer = ByteBuffer.wrap(packagePayload, 0, 41);
buffer.put(dataMergeCommand);
buffer.putLong(uuid.getMostSignificantBits());
buffer.putLong(uuid.getLeastSignificantBits());
buffer.putShort(packetCount);
buffer.putShort(i);
buffer.putInt(data.length);
buffer.putInt(i*packetLength);
System.arraycopy(data, 0, packagePayload, 41, packetLength);
dataz[i]=packagePayload;
}
byte[] packagePayload = new byte[packetLength+41];
ByteBuffer buffer = ByteBuffer.wrap(packagePayload, 0, 41);
buffer.put(dataMergeCommand);
buffer.putLong(uuid.getMostSignificantBits());
buffer.putLong(uuid.getLeastSignificantBits());
buffer.putShort(packetCount);
buffer.putShort((short) (packetCount-1));
buffer.putInt(data.length);
buffer.putInt((packetCount-1)*packetLength);
System.arraycopy(data, 0, packagePayload, 41, lastPacketLength);
dataz[packetCount-1]=packagePayload;
}
}
public void dispose() {
isReceiving = false;
socket.close();
packetReceiver.interrupt();
}
}

View File

@ -0,0 +1,200 @@
package com.bernard.murder.audio;
import java.io.IOException;
import java.net.SocketAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;
import com.bernard.murder.BytesUtils;
public class SpeakerServer {
SourceDataLine speakerLine;
int packetLength = 9728;
int speakerId;
String speakerName;
UUID askedUUID;
Serveur serveur;
Map<Integer,String> mics;
volatile boolean isMicListUpToDate = false;
int listeningTo = -1;
SocketAddress masterAddress;
Runnable serverAnswered;
public SpeakerServer(SocketAddress serveur,String speakerName,SourceDataLine speaker) {
this.speakerName = speakerName;
this.masterAddress = serveur;
this.speakerLine = speaker;
try {
initServer();
initializeAudioId();
} catch (SocketException | UnknownHostException e) {
e.printStackTrace();
}
}
public void initServer() throws SocketException, UnknownHostException {
serveur = new Serveur(this::receiveCommand,AudioServer.communicationPort);
}
public void initializeSpeakerDevice() throws LineUnavailableException {
speakerLine.open(AudioServer.formatAudio);
packetLength = speakerLine.getBufferSize()/5;
}
public void initializeAudioId() {
ByteBuffer buffer = ByteBuffer.allocate(AudioServer.packetMaxSize);
askedUUID = UUID.randomUUID();
buffer.put(AudioServer.DECLARE_NUMBER);
buffer.putLong(askedUUID.getMostSignificantBits());
buffer.putLong(askedUUID.getLeastSignificantBits());
buffer.put(AudioServer.SPEAKER_DEVICE);
BytesUtils.writeString(buffer, speakerName);
try {
serveur.sendData(buffer,masterAddress);
} catch (IOException e) {
e.printStackTrace();
}
}
public void askForStream(int micId) {
ByteBuffer buffer = ByteBuffer.allocate(AudioServer.packetMaxSize);
buffer.put(AudioServer.START_STREAMING);
buffer.putInt(micId);
buffer.putInt(speakerId);
try {
serveur.sendData(buffer,masterAddress);
listeningTo = micId;
} catch (IOException e) {
e.printStackTrace();
}
}
public void stopStreaming() {
ByteBuffer buffer = ByteBuffer.allocate(AudioServer.packetMaxSize);
buffer.put(AudioServer.STOP_STREAMING);
buffer.putInt(listeningTo);
buffer.putInt(speakerId);
try {
serveur.sendData(buffer,masterAddress);
} catch (IOException e) {
e.printStackTrace();
}
}
public void askAudioList() {
ByteBuffer buffer = ByteBuffer.allocate(AudioServer.packetMaxSize);
buffer.put(AudioServer.ASK_AUDIO_LIST);
try {
serveur.sendData(buffer,masterAddress);
} catch (IOException e) {
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) {
byte commande = data.get();
System.out.println("Commande recue : "+commande);
switch (commande) {
case AudioServer.AUDIO_STREAM:
int micId = data.getInt();
if(micId != listeningTo)return;
data.compact();
byte[] audioData=new byte[data.remaining()];
data.get(audioData);//XXX Check wether audio data starts at position and not at 0
speakerLine.write(audioData, 0, packetLength);
break;
case AudioServer.OK_ID:
UUID uuid = new UUID(data.getLong(), data.getLong());
byte deviceType = data.get();
int deviceId = data.getInt();
if(!askedUUID.equals(uuid) || deviceType!=AudioServer.SPEAKER_DEVICE)
return;
speakerId = deviceId;
serverAnswered.run();
if(speakerLine==null)
try {
initializeSpeakerDevice();
} catch (LineUnavailableException e) {
e.printStackTrace();
}
break;
case AudioServer.GIVE_AUDIO_LIST:
int micCount = data.getInt();
mics = new HashMap<Integer, String>(micCount);
for(int i = 0; i<micCount;i++) {
int thisMicId = data.getInt();
mics.put(thisMicId,BytesUtils.readString(data));
}
isMicListUpToDate=true;
break;
default:
break;
}
}
public void dispose() {
speakerLine.close();
serveur.dispose();
}
public void setServerAnswered(Runnable serverAnswered) {
this.serverAnswered = serverAnswered;
}
}

View File

@ -1,12 +1,20 @@
package com.bernard.murder.game;
import static com.bernard.murder.ParseUtils.mappingKeys;
import static com.bernard.murder.ParseUtils.node;
import static com.bernard.murder.ParseUtils.parseTimeLength;
import static com.bernard.murder.ParseUtils.sequenceStream;
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.FileWriter;
import java.io.IOException;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.Spliterator;
@ -16,10 +24,13 @@ import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import com.amihaiemil.eoyaml.Node;
import com.amihaiemil.eoyaml.Yaml;
import com.amihaiemil.eoyaml.YamlInput;
import com.amihaiemil.eoyaml.YamlMapping;
import com.amihaiemil.eoyaml.YamlMappingBuilder;
import com.amihaiemil.eoyaml.YamlNode;
import com.amihaiemil.eoyaml.YamlPrinter;
import com.amihaiemil.eoyaml.YamlSequence;
import com.bernard.murder.ParseUtils;
import com.bernard.murder.model.Action;
@ -31,89 +42,89 @@ import com.bernard.murder.model.Status;
public class GameCreator {
public static Partie genFromFile(File toread) throws IOException{
YamlInput input = Yaml.createYamlInput(toread);
YamlMapping globalMap = input.readYamlMapping();
YamlMapping yjoueurs = globalMap.yamlMapping("joueurs");
System.out.println(yjoueurs);
YamlMapping yjoueurs = getMapping(globalMap.value("joueurs"));
// Pour pouvoir créer les objets et les espaces personnels
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()
.stream()
.map(n -> new Action(node(n), parseTimeLength(yactions.string(n))))
.map(n -> new Action(n.asScalar().value(), parseTimeLength(yactions.string(n))))
.collect(Collectors.toSet());
Map<String,Set<Action>> persActions = playerNames.stream()
.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)
.map(n ->ParseUtils.node(n))
.map(n ->n.asScalar().value())
.collect(Collectors.toSet());
Map<String,Set<Objet>> persObjets = playerNames.stream()
.collect(Collectors.toMap(Function.identity(),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(node(n))).collect(Collectors.toSet());
YamlSequence ystatus = getSequence(globalMap.value("status"));
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(
n -> node(n),
n-> parseHiddenObjects(yespaces.yamlSequence(n))
n -> n.asScalar().value(),
n-> parseHiddenObjects(getSequence(yespaces.value(n)))
));
Set<Piece> espaceObjets = yespaces.keys().stream()
.map(n -> new Piece(node(n), objetsDansEspaces.get(node(n))))
.map(n -> new Piece(n.asScalar().value(), objetsDansEspaces.get(n.asScalar().value())))
.collect(Collectors.toSet());
YamlMapping yespacesPersos = globalMap.yamlMapping("espacesPersos");
YamlMapping yespacesPersos = getMapping(globalMap.value("espacesPersos"));
Map<String,Set<Piece>> persespacesPersos = playerNames.stream().collect(Collectors.toMap(
Function.identity(),
p -> yespacesPersos.keys().stream()
.map(e -> new Piece(
String.format(node(e), p),
parseHiddenObjects(yespacesPersos.yamlSequence(e),p)
String.format(e.asScalar().value(), p),
parseHiddenObjects(getSequence(yespacesPersos.value(e)),p)
))
.collect(Collectors.toSet())
));
//Per perso settings
for(YamlNode pn : yjoueurs.keys()) {
String pname = node(pn);
System.out.println(pn);
System.out.println(yjoueurs.yamlMapping(pn));
String pname = pn.asScalar().value();
persActions.get(pname).addAll(
yjoueurs.yamlMapping(pn).yamlMapping("actions").keys()
getMapping(getMapping(yjoueurs.value(pn)).value("actions")).keys()
.stream()
.map(n -> new Action(node(n), 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())
);
persObjets.get(pname).addAll(
StreamSupport.stream(Spliterators.spliteratorUnknownSize(yjoueurs.yamlMapping(pn).yamlSequence("inventaire").iterator(),Spliterator.ORDERED),false)
.map(n ->ParseUtils.node(n))
StreamSupport.stream(Spliterators.spliteratorUnknownSize(getSequence(getMapping(yjoueurs.value(pn)).value("inventaire")).iterator(),Spliterator.ORDERED),false)
.map(n ->n.asScalar().value())
.map(o ->new Objet(o))
.collect(Collectors.toSet())
);
if(yjoueurs.yamlMapping(pn).yamlMapping("espacePerso")!= null)
if(isMapping(getMapping(yjoueurs.value(pn)).value("espacePerso")))
// Plusieurs espaces
yjoueurs.yamlMapping(pn).yamlMapping("espacePerso").keys().forEach(n ->
getMapping(getMapping(yjoueurs.value(pn)).value("espacePerso")).keys().forEach(n ->
persespacesPersos.get(pname)
.stream()
.filter(p -> p.getNom().contentEquals(node(n)))
.filter(p -> p.getNom().contentEquals(n.asScalar().value()))
.findAny()
.orElseGet(() -> new Piece(node(n)))
.insertObjects(parseHiddenObjects(yjoueurs.yamlMapping(pn).yamlMapping("espacePerso").yamlSequence(n)))
.orElseGet(() -> new Piece(n.asScalar().value()))
.insertObjects(parseHiddenObjects(getSequence(getMapping(getMapping(yjoueurs.value(pn)).value("espacePerso")).value(n))))
);
else
((persespacesPersos.get(pname).isEmpty())?
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")))));
}
@ -126,8 +137,8 @@ public class GameCreator {
persActions.get(p),
status.stream().filter(st -> sequenceStream(ystatus)
.filter(n -> n instanceof YamlMapping)
.filter(n -> ((YamlMapping)n).string(st.getName())!=null)
.filter(n -> ((YamlMapping)((YamlMapping)n).yamlMapping(st.getName())).string("onStart").contentEquals("true"))
.filter(n -> getMapping(n).string(st.getName())!=null)
.filter(n -> getMapping(getMapping(n).value(st.getName())).string("onStart").contentEquals("true"))
.findAny().isPresent())
.collect(Collectors.toSet()),
persespacesPersos.get(p)
@ -138,12 +149,130 @@ public class GameCreator {
private static Map<Objet,Integer> parseHiddenObjects(YamlSequence sequence,Object... nameFormat){
return sequenceStream(sequence).collect(Collectors.toMap(
on -> new Objet(String.format((on instanceof YamlMapping)?(((YamlMapping)on).keys().stream().map(nn -> node(nn)).findAny().get()):node(on),nameFormat)),
on -> ((on instanceof YamlMapping)?(((YamlMapping)on).integer(((YamlMapping)on).keys().stream().findAny().get())):-1)
on -> new Objet(String.format((on.type()==Node.MAPPING)?(on.asMapping().keys().stream().map(nn -> nn.asScalar().value()).findAny().get()):on.asScalar().value(),nameFormat)),
on -> ((on.type()==Node.MAPPING)?(on.asMapping().integer(on.asMapping().keys().stream().findAny().get())):-1)
));
}
private static Map<Objet,Integer> parseHiddenObjects(YamlSequence sequence){
return parseHiddenObjects(sequence, new Object[0]);
}
public static final void quickSave(File f, Partie p, YamlMapping minelsMap) throws IOException {
YamlMappingBuilder globalMapping = Yaml.createYamlMappingBuilder()
.add("personnages",
ParseUtils.setToMapSY(p.personnagesStream().collect(Collectors.toSet()),
perso -> perso.getNom(),
perso ->
Yaml.createYamlMappingBuilder()
.add("actions",ParseUtils.setToMapSY(perso.getActions(),
act -> act.getName(),
act -> Yaml.createYamlMappingBuilder()
.add("basetime", Long.toString(act.getBasetime()))
.add("triggerTime", Long.toString(act.getTriggertime()))
.build()))
.add("espacePerso",ParseUtils.setToMapSY(perso.streamEspacesPersos().collect(Collectors.toSet()),
esp -> esp.getNom(),
esp -> ParseUtils.setToSeqY(esp.streamHiddenObjects().map(etr -> Yaml.createYamlMappingBuilder().add(etr.getKey().getNom(), Integer.toString(etr.getValue())).build()).collect(Collectors.toSet()))
))
.add("status", ParseUtils.setToSeqS(perso.streamStatus().map(Status::getName).collect(Collectors.toSet())))
.add("inventaire", ParseUtils.setToSeqS(perso.getInventaire().stream().map(Objet::getNom).collect(Collectors.toSet()))).build()
))
.add("status", ParseUtils.setToSeqS(p.statuzStream().map(Status::getName).collect(Collectors.toSet())))
.add("pieces",ParseUtils.setToMapSY(p.piecesStream().collect(Collectors.toSet()),
Piece::getNom,
esp -> ParseUtils.setToSeqY(esp.streamHiddenObjects().map(etr -> Yaml.createYamlMappingBuilder().add(etr.getKey().getNom(), Integer.toString(etr.getValue())).build()).collect(Collectors.toSet()))
))
.add("minels", minelsMap);
YamlPrinter printer = Yaml.createYamlPrinter(new FileWriter(f));
printer.print(globalMapping.build());
}
public static final QuicksavedPartie readQuickSave(File f) throws IOException {
YamlInput input = Yaml.createYamlInput(f);
YamlMapping globalMap = input.readYamlMapping();
YamlSequence ystatus = getSequence(globalMap.value("status"));
Set<Status> status = sequenceStream(ystatus).map(n -> new Status(n.asScalar().value())).collect(Collectors.toSet());
YamlMapping yespaces = getMapping(globalMap.value("pieces"));
Map<String, Map<Objet, Integer>> objetsDansEspaces = yespaces.keys().stream().collect(Collectors.toMap(
n -> watch(watch(n).asScalar().value()),
n-> parseHiddenObjects(getSequence(yespaces.value(n)))
));
Set<Piece> espaceObjets = yespaces.keys().stream()
.map(n -> new Piece(n.asScalar().value(), objetsDansEspaces.get(n.asScalar().value())))
.collect(Collectors.toSet());
YamlMapping yjoueurs = getMapping(globalMap.value("personnages"));
Set<Personnage> personnages = new HashSet<Personnage>();
for(YamlNode pn : yjoueurs.keys()) {
String pname = pn.asScalar().value();
Set<Action> actions = getMapping(getMapping(yjoueurs.value(pn)).value("actions")).keys()
.stream()
.map(n -> new Action(n.asScalar().value(), Long.parseLong(getMapping(getMapping(getMapping(yjoueurs.value(pn)).value("actions")).value(n)).string("basetime")),
Long.parseLong(getMapping(getMapping(getMapping(yjoueurs.value(pn)).value("actions")).value(n)).string("triggerTime"))))
.collect(Collectors.toSet());
Set<Objet> inventaire =
StreamSupport.stream(Spliterators.spliteratorUnknownSize(getSequence(getMapping(yjoueurs.value(pn)).value("inventaire")).iterator(),Spliterator.ORDERED),false)
.map(n ->n.asScalar().value())
.map(o ->new Objet(o))
.collect(Collectors.toSet());
Set<Piece> espacesPerso = getMapping(getMapping(yjoueurs.value(pn)).value("espacePerso")).keys().stream().map(n ->
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(
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());
personnages.add(new Personnage(pname, inventaire, actions, persoStatus, espacesPerso));
}
YamlMapping minelsMap = getMapping(globalMap.value("minels"));
return new QuicksavedPartie(new Partie(personnages, status, espaceObjets),minelsMap);
}
public static class QuicksavedPartie{
Partie partie;
YamlMapping minelsMap;
public QuicksavedPartie(Partie partie, YamlMapping minelsMap) {
this.partie = partie;
this.minelsMap = minelsMap;
}
public Partie getPartie() {
return partie;
}
public YamlMapping getMinelsMap() {
return minelsMap;
}
}
}

View File

@ -1,13 +1,126 @@
package com.bernard.murder.game;
import java.io.File;
import java.io.IOException;
import java.time.Instant;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import javax.swing.Timer;
import com.amihaiemil.eoyaml.Yaml;
import com.amihaiemil.eoyaml.YamlMapping;
import com.bernard.murder.model.Inventaire;
import com.bernard.murder.model.Objet;
import com.bernard.murder.model.Partie;
import com.bernard.murder.model.Personnage;
public class GameManager {
Partie partie;
Map<Inventaire,Set<Runnable>> inventoryUpdateListeners;
long startTime;
Timer quickSaver;
Supplier<YamlMapping> minelsQuicksaver;
public GameManager(Partie partie) {
this.partie = partie;
this.inventoryUpdateListeners = new HashMap<Inventaire, Set<Runnable>>();
this.minelsQuicksaver = () -> Yaml.createYamlMappingBuilder().build();
startTime = System.currentTimeMillis();
quickSaver = new Timer(10_000, e -> this.quickSave());
quickSaver.start();
}
public synchronized void moveObjet(Objet o, Inventaire toInv) {
Inventaire inv = partie.findObjectInventory(o);
System.out.println("Moving "+o+" from "+inv+" to "+toInv);
inv.removeObjet(o);
toInv.addObjet(o);
inventoryUpdate(inv);
inventoryUpdate(toInv);
}
public void inventoryUpdate(Inventaire inv) {
if(!inventoryUpdateListeners.containsKey(inv))return;
for(Runnable r : inventoryUpdateListeners.get(inv))
r.run();
}
public void dumpCurrentState() {
System.out.println(partie);
}
public void addInventoryUpdateListener(Inventaire inv, Runnable runnable) {
if(!inventoryUpdateListeners.containsKey(inv))
inventoryUpdateListeners.put(inv, new HashSet<Runnable>());
inventoryUpdateListeners.get(inv).add(runnable);
}
public void quickSave() {
System.out.println("Quicksaving");
File toSave = new File(quickSaveFilename());
File tempOldSave = new File(quickSaveFilename()+".tmp");
if(toSave.exists())toSave.renameTo(tempOldSave);
try {
GameCreator.quickSave(toSave, partie,minelsQuicksaver.get());
System.out.println("Quicksaved");
if(tempOldSave.exists())tempOldSave.delete();
} catch (IOException e) {
e.printStackTrace();
}
}
public String quickSaveFilename() {
return "murder-"+DateTimeFormatter.ofPattern("uu-MM-dd_HH'h'mm").withZone(ZoneId.systemDefault()).withLocale(Locale.getDefault()).format(Instant.ofEpochMilli(startTime))+".bernard.quickmurder";
}
public Set<Inventaire> getEveryInventaire() {
Set<Inventaire> inventaires = new HashSet<Inventaire>();
inventaires.addAll(partie.pieces());
inventaires.addAll(partie.personnages());
partie.personnagesStream().forEach(p -> inventaires.addAll(p.espacePersos()));
return inventaires;
}
public Set<Inventaire> getEveryInventaireByName(Set<String> names) {
Set<Inventaire> inventaires = new HashSet<Inventaire>();
inventaires.addAll(partie.pieces());
inventaires.addAll(partie.personnages());
partie.personnagesStream().forEach(p -> inventaires.addAll(p.espacePersos()));
return inventaires.stream().filter(i -> names.contains(i.getInventoryName())).collect(Collectors.toSet());
}
public Personnage getPersoByName(String key) {
return partie.personnagesStream().filter(p -> key.equalsIgnoreCase(p.getNom())).findAny().orElse(null);
}
public void bindMinelQuicksaver(Supplier<YamlMapping> minelsQuicksaver) {
this.minelsQuicksaver = minelsQuicksaver;
}
public Inventaire getInventoryByName(String name) {
Set<Inventaire> inventaires = new HashSet<Inventaire>();
inventaires.addAll(partie.pieces());
inventaires.addAll(partie.personnages());
partie.personnagesStream().forEach(p -> inventaires.addAll(p.espacePersos()));
return inventaires.stream().filter(i -> name.equalsIgnoreCase(i.getInventoryName())).findAny().orElseGet(()->{
System.out.println("JE n'ai pas trouvé l'inventaire "+name+" dans la liste "+inventaires.stream().map(Inventaire::getInventoryName).collect(Collectors.joining(",")));
return null;
});
}
}

View File

@ -9,9 +9,17 @@ public class Action implements Cloneable{
public Action(String action, long basetime) {
this.action = action;
this.basetime = basetime;
this.triggertime = Long.MIN_VALUE;
this.triggertime = 0;
}
public Action(String action, long basetime, long triggertime) {
this.action = action;
this.basetime = basetime;
this.triggertime = triggertime;
}
@Override
public Action clone() {
Action actions = new Action(action, basetime);
@ -24,6 +32,38 @@ public class Action implements Cloneable{
return "Action [action=" + action + ", basetime=" + basetime + ", triggertime=" + triggertime + ", transient id=" + System.identityHashCode(this) + "]";
}
public String getName() {
return action;
}
public boolean canBeLaunched() {
return System.currentTimeMillis()-triggertime-basetime>0;
}
public void launch() {
triggertime=System.currentTimeMillis();
}
public boolean hasFinished() {
return triggertime + basetime - System.currentTimeMillis()<0;
}
public long timeToWaitLeft() {
return basetime - System.currentTimeMillis() + triggertime;
}
public long dateReset() {
return triggertime + basetime;
}
public long getBasetime() {
return basetime;
}
public long getTriggertime() {
return triggertime;
}
}

View File

@ -6,4 +6,10 @@ public interface Inventaire {
Set<Objet> getObjects();
void removeObjet(Objet o);
void addObjet(Objet o);
String getInventoryName();
}

View File

@ -1,10 +1,12 @@
package com.bernard.murder.model;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Stream;
public class Partie {
Set<Personnage> personnages;
Set<Status> statuz;
Set<Piece> piece;
@ -34,6 +36,35 @@ public class Partie {
return "Partie [personnages=" + personnages + ", statuz=" + statuz + ", piece=" + piece + "]";
}
public Inventaire findObjectInventory(Objet o) {
Optional<Personnage> persoInv = personnages.stream().filter(p -> p.inventaire.contains(o)).findAny();
if(persoInv.isPresent())return persoInv.get();
Optional<Piece> persoInvRoom = personnages.stream()
.map(p -> p.espacesPersos.stream()
.filter(ep -> ep.contenu.keySet().contains(o)).findAny())
.filter(Optional::isPresent).map(Optional::get).findAny();
if(persoInvRoom.isPresent())return persoInvRoom.get();
Optional<Piece> invRoom = piece.stream()
.filter(ep -> ep.contenu.keySet().contains(o)).findAny();
if(invRoom.isPresent())return invRoom.get();
return null;
}
public Stream<Status> statuzStream() {
return statuz.stream();
}
public Set<Piece> pieces() {
return piece;
}
public Set<Personnage> personnages() {
return personnages;
}
}

View File

@ -34,6 +34,10 @@ public class Personnage implements Inventaire{
return inventaire;
}
public Set<Action> getActions() {
return actions;
}
public Stream<Piece> streamEspacesPersos(){
return espacesPersos.stream();
}
@ -55,5 +59,41 @@ public class Personnage implements Inventaire{
@Override
public void removeObjet(Objet o) {
System.out.println("Avant :"+inventaire);
this.inventaire.remove(o);
System.out.println("Après :"+inventaire);
}
@Override
public void addObjet(Objet o) {
this.inventaire.add(o);
}
public Stream<Status> streamStatus() {
return status.stream();
}
@Override
public String getInventoryName() {
return "Inventaire de "+getNom();
}
public Set<Piece> espacePersos() {
return espacesPersos;
}
}

View File

@ -2,7 +2,9 @@ package com.bernard.murder.model;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.stream.Stream;
public class Piece implements Inventaire{
@ -37,6 +39,24 @@ public class Piece implements Inventaire{
contenu.putAll(objs);
}
@Override
public void removeObjet(Objet o) {
this.contenu.remove(o);
}
@Override
public void addObjet(Objet o) {
this.contenu.put(o,-1);
}
public Stream<Entry<Objet, Integer>> streamHiddenObjects() {
return contenu.entrySet().stream();
}
@Override
public String getInventoryName() {
return nom;
}

View File

@ -1,6 +0,0 @@
module murder{
requires com.amihaiemil.eoyaml;
requires java.desktop;
}

View File

@ -0,0 +1,106 @@
package com.bernard.murder.util.view;
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.dnd.DropTargetDragEvent;
import java.awt.dnd.DropTargetDropEvent;
import java.awt.dnd.DropTargetEvent;
import java.awt.dnd.DropTargetListener;
import java.util.TooManyListenersException;
import javax.swing.JTabbedPane;
import com.bernard.murder.view.minel.objetDnD.NotADropTarget;
public class MouseReactiveTabbedPane extends JTabbedPane {
private static final long serialVersionUID = -4985256252193243545L;
long waitTime = 500_000_000;
Thread plannedThread;
int dropAcceptance;
int hoverIndex = -1;
long enteredTime = -1;
public MouseReactiveTabbedPane(int tabPlacement) {
super(tabPlacement);
final MouseReactiveTabbedPane pane = this;
this.setDropTarget(new NotADropTarget());
try {
this.getDropTarget().addDropTargetListener(new DropTargetListener() {
@Override
public void dragOver(DropTargetDragEvent dtde) {
int tab = getTab(dtde);
System.out.println(">"+tab+"/"+hoverIndex+"-"+enteredTime);
if(tab==-1) {
enteredTime=-1;
hoverIndex=-1;
return;
}
if(tab!=hoverIndex) {
//On viens d'entrer dans un nouveau tab !
enteredTime=System.nanoTime();
hoverIndex=tab;
if(plannedThread==null){
plannedThread = new Thread(() -> {
while(System.nanoTime()>enteredTime+waitTime) {
try {
Thread.sleep(2);
} catch (InterruptedException e1) {}
}
if(getTab() == hoverIndex)
pane.setSelectedIndex(hoverIndex);
hoverIndex = -1;
enteredTime = -1;
plannedThread = null;
});
plannedThread.start();
}
}
dtde.acceptDrag(dropAcceptance);
}
@Override
public void dropActionChanged(DropTargetDragEvent dtde) {}
@Override
public void drop(DropTargetDropEvent dtde) {}
@Override
public void dragExit(DropTargetEvent dte) {
enteredTime=-1;
hoverIndex=-1;
return;
}
@Override
public void dragEnter(DropTargetDragEvent e) {}
});
} catch (TooManyListenersException e1) {
e1.printStackTrace();
}
}
public int getTab(DropTargetDragEvent dtde) {
for (int i = 0; i < this.getTabCount(); i++)
if (this.getBoundsAt(i).contains(dtde.getLocation()))
return i;
return -1;
}
public int getTab() {
Point loc = MouseInfo.getPointerInfo().getLocation();
Point screen = this.getLocationOnScreen();
Point point = new Point(loc.x - screen.x, loc.y - screen.y);
for (int i = 0; i < this.getTabCount(); i++)
if (this.getBoundsAt(i).contains(point))
return i;
return -1;
}
}

View File

@ -0,0 +1,18 @@
package com.bernard.murder.util.view;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
public abstract class SimpleDocumentListener implements DocumentListener {
@Override
public void insertUpdate(DocumentEvent e) {
changedUpdate(e);
}
@Override
public void removeUpdate(DocumentEvent e) {
changedUpdate(e);
}
}

View File

@ -0,0 +1,138 @@
package com.bernard.murder.view;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Line;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.Mixer;
import javax.sound.sampled.Mixer.Info;
import javax.sound.sampled.SourceDataLine;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JTextField;
import com.bernard.murder.audio.AudioServer;
import com.bernard.murder.audio.SpeakerServer;
public class EnceinteServeurFrame extends JFrame{
private static final long serialVersionUID = -2023529082781210475L;
SpeakerServer serveur;
String deviceName;
public EnceinteServeurFrame(String deviceName) {
this.setSize(300, 500);
this.setMinimumSize(new Dimension(100, 200));
this.setLocationRelativeTo(null);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setTitle("Serveur audio");
this.deviceName = deviceName;
this.setContentPane(genContentPan());
this.setVisible(true);
}
public JPanel genContentPan() {
JPanel panel = new JPanel(new BorderLayout());
InformedSourceDataline[] marray = getEnceinteList();
JList<InformedSourceDataline> enceinteListe = new JList<InformedSourceDataline>(marray);
JPanel masterPanel = new JPanel(new BorderLayout());
JTextField masterIP = new JTextField("192.168.1.1");
JButton serverControl = new JButton("Lancer");
masterPanel.add(serverControl,BorderLayout.EAST);
masterPanel.add(masterIP,BorderLayout.CENTER);
JList<NamedMicrophone> mics = new JList<>();
serverControl.addActionListener(e->{
if(enceinteListe.getSelectedValue()==null)return;
serverControl.setEnabled(false);
if(serveur!=null) {
serveur.dispose();
serveur = null;
serverControl.setText("Lancer");
}else {
serveur = new SpeakerServer(new InetSocketAddress(masterIP.getText(), AudioServer.communicationPort), deviceName,enceinteListe.getSelectedValue().tdl);
serveur.setServerAnswered(()->{
serverControl.setText("Arrêter");
List<NamedMicrophone> list = serveur.getAudioList().entrySet().stream().map(et -> new NamedMicrophone(et.getKey(), et.getValue())).collect(Collectors.toList());
NamedMicrophone[] micarray = new NamedMicrophone[list.size()];
list.toArray(micarray);
mics.setListData(micarray);
});
serverControl.setText("Lancement");
}
serverControl.setEnabled(true);
});
panel.add(masterPanel,BorderLayout.NORTH);
panel.add(mics,BorderLayout.SOUTH);
panel.add(enceinteListe,BorderLayout.CENTER);
return panel;
}
public static final InformedSourceDataline[] getEnceinteList() {
List<InformedSourceDataline> linfo = new ArrayList<>();
Line.Info srcInfo = new Line.Info(SourceDataLine.class);
Mixer.Info[] mixerInfos = AudioSystem.getMixerInfo();
for (Mixer.Info info : mixerInfos) {
Mixer mixer = AudioSystem.getMixer(info);
try {
SourceDataLine tdl = (SourceDataLine)mixer.getLine(srcInfo);
linfo.add(new InformedSourceDataline(tdl, info));
} catch (LineUnavailableException|IllegalArgumentException e) {}
}
InformedSourceDataline[] marray = new InformedSourceDataline[linfo.size()];
linfo.toArray(marray);
return marray;
}
public static class InformedSourceDataline {
SourceDataLine tdl;
Mixer.Info mixerInfo;
public InformedSourceDataline(SourceDataLine tdl, Info mixerInfo) {
this.tdl = tdl;
this.mixerInfo = mixerInfo;
}
@Override
public String toString() {
return mixerInfo.getDescription();
}
}
public static class NamedMicrophone {
int micId;
String micName;
public NamedMicrophone(int micId, String micName) {
this.micId = micId;
this.micName = micName;
}
@Override
public String toString() {
return micName;
}
}
}

View File

@ -1,60 +0,0 @@
package com.bernard.murder.view;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.swing.JPanel;
import com.bernard.murder.model.Inventaire;
import com.bernard.murder.model.Objet;
public class GlobalUIManager implements MouseListener{
public GlobalUIManager(JPanel globalPan) {
globalPan.addMouseListener(this);
}
Set<Objet> currentUIselection = new HashSet<Objet>();
Map<JPanel,Inventaire> inventaire = new HashMap<>();
@Override
public void mouseClicked(MouseEvent e) {
}
@Override
public void mousePressed(MouseEvent e) {
System.out.println(e.getSource());
System.out.println(e.getComponent());
}
@Override
public void mouseReleased(MouseEvent e) {
if(e.getButton()==MouseEvent.NOBUTTON) {
currentUIselection.clear();
}
}
@Override
public void mouseEntered(MouseEvent e) {
if(e.getButton()==MouseEvent.NOBUTTON) {
// Le clic a peut être été laché à l'exterieur
currentUIselection.clear();
}
}
@Override
public void mouseExited(MouseEvent e) {
}
}

View File

@ -0,0 +1,104 @@
package com.bernard.murder.view;
import java.awt.CardLayout;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DropTargetDragEvent;
import java.awt.dnd.DropTargetDropEvent;
import java.awt.dnd.DropTargetEvent;
import java.awt.dnd.DropTargetListener;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
public class HoverSelect implements DropTargetListener,Runnable{
long enteredTime = -1;
long waitTime = 500_000_000;
Runnable onSelect;
Thread plannedThread;
int dropAcceptance;
public HoverSelect(Runnable onSelect,long waitTime,int shouldAcceptDrop){
this.onSelect = onSelect;
this.waitTime = waitTime;
this.dropAcceptance = shouldAcceptDrop;
}
public HoverSelect(CardLayout layout, JPanel panel, String identifier, long waitTime,int shouldAcceptDrop) {
this(() -> layout.show(panel, identifier),waitTime,shouldAcceptDrop);
}
public HoverSelect(JTabbedPane tabbedPan, int index, long waitTime,int shouldAcceptDrop) {
this(() -> tabbedPan.setSelectedIndex(index),waitTime,shouldAcceptDrop);
}
public HoverSelect(Runnable onSelect,int shouldAcceptDrop){
this.onSelect = onSelect;
this.dropAcceptance = shouldAcceptDrop;
}
public HoverSelect(CardLayout layout, JPanel panel, String identifier,int shouldAcceptDrop) {
this(() -> layout.show(panel, identifier),shouldAcceptDrop);
}
public HoverSelect(Runnable onSelect,long waitTime){
this(onSelect,waitTime,DnDConstants.ACTION_NONE);
}
public HoverSelect(CardLayout layout, JPanel panel, String identifier, long waitTime) {
this(() -> layout.show(panel, identifier),waitTime,DnDConstants.ACTION_NONE);
}
public HoverSelect(JTabbedPane tabbedPan, int index, int shouldAcceptDrop) {
this(() -> tabbedPan.setSelectedIndex(index),shouldAcceptDrop);
}
public HoverSelect(JTabbedPane tabbedPan, int index, long waitTime) {
this(() -> tabbedPan.setSelectedIndex(index),waitTime,DnDConstants.ACTION_NONE);
}
public HoverSelect(Runnable onSelect){
this(onSelect, DnDConstants.ACTION_NONE);
}
public HoverSelect(CardLayout layout, JPanel panel, String identifier) {
this(() -> layout.show(panel, identifier),DnDConstants.ACTION_NONE);
}
public HoverSelect(JTabbedPane tabbedPan, int index) {
this(() -> tabbedPan.setSelectedIndex(index),DnDConstants.ACTION_NONE);
}
@Override
public void dragEnter(DropTargetDragEvent e) {
enteredTime = System.nanoTime();
System.out.println("entré");
plannedThread = new Thread(()-> {
try {
Thread.sleep(waitTime/1_000_000, (int)(waitTime%1_000_000));
onSelect.run();
} catch (InterruptedException e1) {}
});
plannedThread.run();
e.acceptDrag(dropAcceptance);
}
@Override
public void dragExit(DropTargetEvent e) {
if(plannedThread!=null)plannedThread.interrupt();
plannedThread = null;
}
@Override
public void dragOver(DropTargetDragEvent dtde) {}
@Override
public void dropActionChanged(DropTargetDragEvent dtde) {}
@Override
public void drop(DropTargetDropEvent dtde) {}
@Override
public void run() {
enteredTime = System.nanoTime();
System.out.println("entré");
plannedThread = new Thread(()-> {
try {
Thread.sleep(waitTime/1_000_000, (int)(waitTime%1_000_000));
onSelect.run();
} catch (InterruptedException e1) {}
});
plannedThread.run();
}
}

View File

@ -0,0 +1,139 @@
package com.bernard.murder.view;
import java.awt.GridLayout;
import java.io.File;
import java.text.DateFormat;
import java.util.Calendar;
import java.util.List;
import java.util.Map;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import com.bernard.murder.game.GameCreator;
import com.bernard.murder.game.GameCreator.QuicksavedPartie;
import com.bernard.murder.game.GameManager;
import com.bernard.murder.model.Partie;
import com.bernard.murder.model.Personnage;
import com.bernard.murder.view.minel.Minel;
public class LauncherFrame extends JFrame{
private static final long serialVersionUID = 5831232688024137883L;
public static void main(String[] args) {
new LauncherFrame();
}
public LauncherFrame() {
try {
//TODO implement flatlaf look&feel
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException e1) {
e1.printStackTrace();
}
this.setTitle("Configuration du terminal");
this.setSize(300, 200);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
JPanel contentPan = new JPanel(new GridLayout(5,1));
JButton creerMaitre = new JButton("Terminal maître");
creerMaitre.addActionListener(e -> {
this.setEnabled(false);
JFileChooser chooser = new JFileChooser();
int returnState = chooser.showOpenDialog(this);
if(returnState==JFileChooser.APPROVE_OPTION) {
File toread = chooser.getSelectedFile();
try {
Partie partie = GameCreator.genFromFile(toread);
GameManager manager = new GameManager(partie);
Map<String,List<Minel>> minelsSup = MinelsCreator.genSupMinels(partie,manager);
Map<Personnage,List<Minel>> minels = MinelsCreator.genPersoMinels(partie,manager);
new MurderatorGameFrame("Murder du "+DateFormat.getDateInstance().format(Calendar.getInstance().getTime()),partie,manager,minelsSup,minels);
this.setVisible(false);
dispose();
}catch(Exception ex) {
ex.printStackTrace();
JOptionPane.showMessageDialog(this, ex.getLocalizedMessage(), "Impossible de lire le fichier", JOptionPane.ERROR_MESSAGE);
}
}
this.setEnabled(true);
});
JButton creerEsclave = new JButton("Terminal esclave");
creerEsclave.setEnabled(false);
JButton creerEnceinte = new JButton("Enceinte");
creerEnceinte.addActionListener(e -> {
this.setEnabled(false);
String name = JOptionPane.showInputDialog(this, "Nom de l'enceinte", "Nom de l'enceinte", JOptionPane.PLAIN_MESSAGE);
if(name != null) {
new EnceinteServeurFrame(name);
this.setVisible(false);
dispose();
} else {
this.setEnabled(true);
}
});
JButton creerMicro = new JButton("Microphone");
creerMicro.addActionListener(e -> {
this.setEnabled(false);
String name = JOptionPane.showInputDialog(this, "Nom du microphone", "Nom du microphone", JOptionPane.PLAIN_MESSAGE);
if(name != null) {
new MicServeurFrame(name);
this.setVisible(false);
dispose();
} else {
this.setEnabled(true);
}
});
JButton chargerSauvegarde = new JButton("Charger Sauvegarde");
chargerSauvegarde.addActionListener(e -> {
this.setEnabled(false);
JFileChooser chooser = new JFileChooser();
int returnState = chooser.showOpenDialog(this);
if(returnState==JFileChooser.APPROVE_OPTION) {
File toread = chooser.getSelectedFile();
try {
QuicksavedPartie qpartie = GameCreator.readQuickSave(toread);
GameManager manager = new GameManager(qpartie.getPartie());
new MurderatorGameFrame("Murder du "+DateFormat.getDateInstance().format(Calendar.getInstance().getTime()),qpartie,manager);
this.setVisible(false);
dispose();
}catch(Exception ex) {
ex.printStackTrace();
JOptionPane.showMessageDialog(this, ex.getLocalizedMessage(), "Impossible de lire le fichier", JOptionPane.ERROR_MESSAGE);
}
}
this.setEnabled(true);
});
contentPan.add(creerMaitre);
contentPan.add(creerEsclave);
contentPan.add(creerMicro);
contentPan.add(creerEnceinte);
contentPan.add(chargerSauvegarde);
this.setContentPane(contentPan);
this.pack();
this.setLocationRelativeTo(null);
this.setVisible(true);
}
}

View File

@ -0,0 +1,113 @@
package com.bernard.murder.view;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.List;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Line;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.Mixer;
import javax.sound.sampled.Mixer.Info;
import javax.sound.sampled.TargetDataLine;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JTextField;
import com.bernard.murder.audio.AudioServer;
import com.bernard.murder.audio.MicServer;
public class MicServeurFrame extends JFrame{
private static final long serialVersionUID = -2023529082781210475L;
MicServer serveur;
String deviceName;
public MicServeurFrame(String deviceName) {
this.setSize(300, 500);
this.setMinimumSize(new Dimension(100, 200));
this.setLocationRelativeTo(null);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setTitle("Serveur audio");
this.deviceName = deviceName;
this.setContentPane(genContentPan());
this.setVisible(true);
}
public JPanel genContentPan() {
JPanel panel = new JPanel(new BorderLayout());
InformedTargetDataline[] marray = getEnceinteList();
JList<InformedTargetDataline> micListe = new JList<InformedTargetDataline>(marray);
JPanel masterPanel = new JPanel(new BorderLayout());
JTextField masterIP = new JTextField("192.168.1.1");
JButton serverControl = new JButton("Lancer");
masterPanel.add(serverControl,BorderLayout.EAST);
masterPanel.add(masterIP,BorderLayout.CENTER);
serverControl.addActionListener(e->{
if(micListe.getSelectedValue()==null)return;
serverControl.setEnabled(false);
if(serveur!=null) {
serveur.dispose();
serveur = null;
serverControl.setText("Lancer");
}else {
serveur = new MicServer(new InetSocketAddress(masterIP.getText(), AudioServer.communicationPort), deviceName,micListe.getSelectedValue().tdl);
serveur.setServerAnswered(()->{
serverControl.setText("Arrêter");
});
serverControl.setText("Lancement");
}
serverControl.setEnabled(true);
});
panel.add(masterPanel,BorderLayout.NORTH);
panel.add(micListe,BorderLayout.CENTER);
return panel;
}
public static final InformedTargetDataline[] getEnceinteList() {
List<InformedTargetDataline> linfo = new ArrayList<>();
Line.Info srcInfo = new Line.Info(TargetDataLine.class);
Mixer.Info[] mixerInfos = AudioSystem.getMixerInfo();
for (Mixer.Info info : mixerInfos) {
Mixer mixer = AudioSystem.getMixer(info);
try {
TargetDataLine tdl = (TargetDataLine)mixer.getLine(srcInfo);
linfo.add(new InformedTargetDataline(tdl, info));
} catch (LineUnavailableException|IllegalArgumentException e) {}
}
InformedTargetDataline[] marray = new InformedTargetDataline[linfo.size()];
linfo.toArray(marray);
return marray;
}
public static class InformedTargetDataline {
TargetDataLine tdl;
Mixer.Info mixerInfo;
public InformedTargetDataline(TargetDataLine tdl, Info mixerInfo) {
this.tdl = tdl;
this.mixerInfo = mixerInfo;
}
@Override
public String toString() {
return mixerInfo.getDescription();
}
}
}

View File

@ -1,5 +1,7 @@
package com.bernard.murder.view;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@ -7,35 +9,51 @@ import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
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.bernard.murder.YamlUtils;
import com.bernard.murder.game.GameCreator.QuicksavedPartie;
import com.bernard.murder.game.GameManager;
import com.bernard.murder.model.Partie;
import com.bernard.murder.model.Personnage;
import com.bernard.murder.view.minel.ActionsMinel;
import com.bernard.murder.view.minel.InventaireMinel;
import com.bernard.murder.view.minel.Minel;
import com.bernard.murder.view.minel.ObjetSearchMinel;
import com.bernard.murder.view.minel.ServeurMinel;
import com.bernard.murder.view.minel.TextPanMinel;
public class MinelsCreator {
public static Map<String, List<Minel>> genSupMinels(Partie partie, GameManager manager) {
Map<String, List<Minel>> outPute = new HashMap<String, List<Minel>>();
public static Map<String, List<Minel>> genSupMinels(Partie qpartie, GameManager manager) {
Map<String, List<Minel>> outPute = new HashMap<String, List<Minel>>();
List<Minel> generalMinels = new ArrayList<Minel>();
partie.piecesStream().map(p -> new InventaireMinel(manager, p)).forEach(m -> generalMinels.add(m));
List<Minel> piecesMinels = new ArrayList<>();
qpartie.piecesStream().map(p -> new InventaireMinel(manager, p)).forEach(m -> piecesMinels.add(m));
generalMinels.add(new TextPanMinel(manager));
generalMinels.add(new ObjetSearchMinel(manager, manager.getEveryInventaire()));
generalMinels.add(new ServeurMinel(manager));
outPute.put("Général", generalMinels);
outPute.put("Pièces", piecesMinels);
return outPute;
}
public static Map<Personnage, List<Minel>> genMinels(Partie partie, GameManager manager) {
public static Map<Personnage, List<Minel>> genPersoMinels(Partie partie, GameManager manager) {
return partie.personnagesStream().collect(Collectors.toMap(Function.identity(), p -> genMinelsForPerso(partie,manager,p)));
}
private static List<Minel> genMinelsForPerso(Partie partie, GameManager manager, Personnage personnage){
List<Minel> minels = new ArrayList<Minel>();
minels.add(new ActionsMinel(manager, personnage));
minels.add(new InventaireMinel(manager, personnage));
personnage.streamEspacesPersos().map(p -> new InventaireMinel(manager, p)).forEach(m -> minels.add(m));
@ -45,5 +63,83 @@ public class MinelsCreator {
return minels;
}
public static Map<String, List<Minel>> genSupMinels(QuicksavedPartie qpartie, GameManager manager) {
return genMinels("sups", qpartie, manager);
}
public static Map<Personnage, List<Minel>> genPersoMinels(QuicksavedPartie qpartie, GameManager manager) {
return genMinels("persos", qpartie, manager).entrySet().stream().collect(Collectors.toMap(e -> manager.getPersoByName(e.getKey()), Map.Entry::getValue));
}
private static Map<String, List<Minel>> genMinels(String minelType,QuicksavedPartie qpartie, GameManager manager) {
Map<String, List<Minel>> outPute = new HashMap<String, List<Minel>>();
YamlMapping supMap = qpartie.getMinelsMap().yamlMapping(minelType);
for(YamlNode n : supMap.keys()) {
YamlSequence minels = supMap.yamlSequence(n);
String minelName = n.asScalar().value();
List<Minel> minelList = new ArrayList<Minel>();
for(YamlNode minelNode : minels) {
YamlMapping minel = minelNode.asMapping();
String className = minel.value("minelClass").asScalar().value();
try {
Class<?> minelClass = Class.forName(className);
Constructor<?> minelConstructor = minelClass.getConstructor(GameManager.class,YamlMapping.class);
Object minelObj = minelConstructor.newInstance(manager,minel);
if(minelObj instanceof Minel) {
minelList.add((Minel) minelObj);
}else {
throw new ClassCastException();
}
} catch (InstantiationException e) {
System.err.println("La classe "+className+" n'est pas prévu pour être instanciable !");
e.printStackTrace();
} catch (IllegalAccessException e) {
System.err.println("Le constructeur (GameManager,YamlMapping) de la classe "+className+" n'est pas public");
e.printStackTrace();
} catch (IllegalArgumentException e) {
System.err.println("Euhhhhhhhhh, ce doit être une erreur de code interne");
e.printStackTrace();
} catch (InvocationTargetException e) {
System.err.println("La recréation du minel de classe "+className+" a foiré");
e.printStackTrace();
} catch (NoSuchMethodException e) {
System.err.println("La classe "+className+" n'a pas de constructeur (GameManager,YamlMapping)");
e.printStackTrace();
} catch (SecurityException e) {
System.err.println("La classe "+className+" n'est pas accessible");
e.printStackTrace();
} catch (ClassNotFoundException e) {
System.err.println("La classe "+className+" n'est pas chargée !");
e.printStackTrace();
} catch (ClassCastException e) {
System.err.println("La classe "+className+" n'est pas un Minel !");
e.printStackTrace();
}
}
outPute.put(minelName, minelList);
}
return outPute;
}
public static YamlMapping createMinelQuicksave(Map<Personnage, List<Minel>> persoMinels, Map<String, List<Minel>> supMinels) {
YamlMappingBuilder supMapBuilder = Yaml.createYamlMappingBuilder();
for(String supName : supMinels.keySet()) {
List<YamlNode> seq = supMinels.get(supName).stream().map(m -> m.saveToYaml().add("minelClass", m.getClass().getName()).build()).collect(Collectors.toList());
supMapBuilder = supMapBuilder.add(supName, YamlUtils.listToSeq(seq));
}
YamlMappingBuilder persoBuilder = Yaml.createYamlMappingBuilder();
for(Personnage perso : persoMinels.keySet())
persoBuilder = persoBuilder.add(perso.getNom(), YamlUtils.listToSeq(persoMinels.get(perso).stream().map(m -> m.saveToYaml().add("minelClass", m.getClass().getName()).build()).collect(Collectors.toList())));
return Yaml.createYamlMappingBuilder()
.add("sups", supMapBuilder.build())
.add("persos", persoBuilder.build())
.build();
}
}

View File

@ -0,0 +1,122 @@
package com.bernard.murder.view;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.util.List;
import java.util.Map;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import com.bernard.murder.ParseUtils;
import com.bernard.murder.game.GameCreator.QuicksavedPartie;
import com.bernard.murder.game.GameManager;
import com.bernard.murder.model.Partie;
import com.bernard.murder.model.Personnage;
import com.bernard.murder.util.view.MouseReactiveTabbedPane;
import com.bernard.murder.view.minel.Minel;
public class MurderatorGameFrame extends JFrame{
private static final long serialVersionUID = -4512350072325470066L;
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.setMinimumSize(new Dimension(200, 100));
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setTitle(frameName);
this.minelsSup = minelsSup;
this.minels = minels;
manager.bindMinelQuicksaver(() -> MinelsCreator.createMinelQuicksave(minels, minelsSup));
this.setContentPane(genGamePane(partie,manager,minelsSup,minels));
this.pack();
this.setLocationRelativeTo(null);
this.setVisible(true);
}
public MurderatorGameFrame(String frameName, QuicksavedPartie qpartie, GameManager manager) {
this(frameName,qpartie.getPartie(),manager,MinelsCreator.genSupMinels(qpartie, manager),MinelsCreator.genPersoMinels(qpartie, manager));
}
public MurderatorGameFrame(String frameName, Partie partie, GameManager manager) {
this(frameName,partie,manager,MinelsCreator.genSupMinels(partie, manager),MinelsCreator.genPersoMinels(partie, manager));
}
public JPanel genGamePane(Partie partie,GameManager manager,Map<String,List<Minel>> minelsSup,Map<Personnage,List<Minel>> minels) {
JPanel globalPan = new JPanel(new BorderLayout());
//Center Panel
MouseReactiveTabbedPane centerPan = new MouseReactiveTabbedPane(JTabbedPane.TOP);
int j = 0;
for(String s : minelsSup.keySet()) {
JPanel centralLocalBpanPan = new JPanel(new GridLayout(2,(minelsSup.get(s).size()+1)/2,-1,-1));
minelsSup.get(s).stream().map(m -> m.genContentPane()).forEach(mpan -> {centralLocalBpanPan.add(mpan);mpan.setBorder(BorderFactory.createLineBorder(ParseUtils.randDarkBlueColor(),2));});
JScrollPane centralLocalPan = new JScrollPane(centralLocalBpanPan);
centerPan.insertTab(s,null,centralLocalPan,null,j++);
System.out.println(j);
}
for(Personnage p : minels.keySet()) {
JPanel centralLocalBpanPan = new JPanel(new GridLayout(2, (minels.get(p).size()+1)/2,-1,-1));
minels.get(p).stream().map(m -> m.genContentPane()).forEach(mpan -> {centralLocalBpanPan.add(mpan);mpan.setBorder(BorderFactory.createLineBorder(ParseUtils.randDarkBlueColor(),2));});
JScrollPane centralLocalPan = new JScrollPane(centralLocalBpanPan);
centerPan.insertTab(p.getNom(),null,centralLocalPan,null,j++);
System.out.println(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);
return globalPan;
}
public String personnageIdentifier(Personnage personnage) {
return String.format("%08X",System.identityHashCode(personnage))+personnage.getNom();
}
}

View File

@ -1,128 +0,0 @@
package com.bernard.murder.view;
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.io.File;
import java.util.List;
import java.util.Map;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import com.bernard.murder.game.GameCreator;
import com.bernard.murder.game.GameManager;
import com.bernard.murder.model.Partie;
import com.bernard.murder.model.Personnage;
import com.bernard.murder.view.minel.Minel;
public class MurderatorMainFrame extends JFrame{
private static final long serialVersionUID = -4512350072325470066L;
public MurderatorMainFrame() {
}
public void startFrame() {
this.setSize(700, 500);
this.setMinimumSize(new Dimension(575, 200));
this.setLocationRelativeTo(null);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setTitle("En attente d'un fichier");
this.setContentPane(genFirstPanel());
this.setVisible(true);
}
public JPanel genFirstPanel() {
JPanel globalPanel = new JPanel();
globalPanel.setLayout(new BoxLayout(globalPanel, BoxLayout.PAGE_AXIS));
JPanel semiPan = new JPanel();
semiPan.setLayout(new BoxLayout(semiPan, BoxLayout.LINE_AXIS));
JButton loadFile = new JButton("Ouvrir un fichier");
loadFile.addActionListener(e -> {
this.setEnabled(false);
JFileChooser chooser = new JFileChooser();
int returnState = chooser.showOpenDialog(this);
if(returnState==JFileChooser.APPROVE_OPTION) {
File toread = chooser.getSelectedFile();
try {
Partie partie = GameCreator.genFromFile(toread);
GameManager manager = new GameManager(partie);
Map<String,List<Minel>> minelsSup = MinelsCreator.genSupMinels(partie,manager);
Map<Personnage,List<Minel>> minels = MinelsCreator.genMinels(partie,manager);
this.setContentPane(genGamePane(partie,manager,minelsSup,minels));
this.getContentPane().repaint(20);
}catch(Exception ex) {
ex.printStackTrace();
JOptionPane.showMessageDialog(this, ex.getLocalizedMessage(), "Impossible de lire le fichier", JOptionPane.ERROR_MESSAGE);
}
}
this.setEnabled(true);
});
semiPan.add(loadFile);
globalPanel.add(semiPan);
return globalPanel;
}
public JPanel genGamePane(Partie partie,GameManager manager,Map<String,List<Minel>> minelsSup,Map<Personnage,List<Minel>> minels) {
JPanel globalPan = new JPanel(new BorderLayout());
GlobalUIManager guim = new GlobalUIManager(globalPan);
//Center Panel
CardLayout centerLayout = new CardLayout();
JPanel centerPan = new JPanel(centerLayout);
for(String s : minelsSup.keySet()) {
JPanel centralLocalBpanPan = new JPanel(new GridLayout(2,(minelsSup.get(s).size()+1)/2));
minelsSup.get(s).stream().map(m -> m.genContentPane(guim)).forEach(mpan -> centralLocalBpanPan.add(mpan));
JScrollPane centralLocalPan = new JScrollPane(centralLocalBpanPan);
centerPan.add(centralLocalPan, s);
}
for(Personnage p : minels.keySet()) {
JPanel centralLocalBpanPan = new JPanel(new GridLayout(2, (minels.get(p).size()+1)/2));
minels.get(p).stream().map(m -> m.genContentPane(guim)).forEach(mpan -> centralLocalBpanPan.add(mpan));
JScrollPane centralLocalPan = new JScrollPane(centralLocalBpanPan);
centerPan.add(centralLocalPan, personnageIdentifier(p));
}
//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));
leftPan.add(localButton);
}
for(Personnage p : minels.keySet()) {
JButton localButton = new JButton(p.getNom());
localButton.addActionListener(e -> centerLayout.show(centerPan, personnageIdentifier(p)));
leftPan.add(localButton);
}
globalPan.add(leftPan, BorderLayout.WEST);
globalPan.add(centerPan, BorderLayout.CENTER);
return globalPan;
}
public String personnageIdentifier(Personnage personnage) {
return String.format("%08X",System.identityHashCode(personnage))+personnage.getNom();
}
}

View File

@ -0,0 +1,9 @@
package com.bernard.murder.view;
import javax.swing.JFrame;
public class SettingsFrame extends JFrame{
private static final long serialVersionUID = 7253551627244719823L;
}

View File

@ -0,0 +1,113 @@
package com.bernard.murder.view.minel;
import java.awt.BorderLayout;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.stream.Collectors;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.Timer;
import com.amihaiemil.eoyaml.Yaml;
import com.amihaiemil.eoyaml.YamlMapping;
import com.amihaiemil.eoyaml.YamlMappingBuilder;
import com.bernard.murder.ParseUtils;
import com.bernard.murder.game.GameManager;
import com.bernard.murder.model.Action;
import com.bernard.murder.model.Personnage;
public class ActionsMinel extends Minel {
public static final String availableText = "Disponible";
public static final String waitingTimeText = "Reste %s, reset à %s";
Personnage personnage;
Collection<Action> updatingActions;
Map<Action,JLabel> actionStatusTexts = new HashMap<>();
Map<Action,JButton> actionButtons = new HashMap<>();
public ActionsMinel(GameManager manager, Personnage perso) {
super(manager);
this.personnage = perso;
updatingActions = new HashSet<Action>();
updatingActions.addAll(perso.getActions());
}
public ActionsMinel(GameManager manager, YamlMapping ym) {
this(manager,manager.getPersoByName(ym.string("personnage")));
}
@Override
public JPanel genContentPane() {
JPanel globalPan = new JPanel(new BorderLayout());
JPanel actionsListPan = new JPanel();
actionsListPan.setLayout(new BoxLayout(actionsListPan, BoxLayout.PAGE_AXIS));
for(Action a : personnage.getActions()) {
JPanel actionControlPanel = new JPanel(new BorderLayout());
JLabel actionName = new JLabel(a.getName());
JButton actionButton = new JButton("GO");
JLabel actionStatusText = new JLabel(availableText);
actionButton.addActionListener(e->launchAction(a));
actionButtons.put(a, actionButton);
actionStatusTexts.put(a, actionStatusText);
actionControlPanel.add(actionButton, BorderLayout.EAST);
actionControlPanel.add(actionName, BorderLayout.NORTH);
actionControlPanel.add(actionStatusText, BorderLayout.SOUTH);
actionsListPan.add(actionControlPanel);
actionsListPan.add(new JSeparator());
Timer timer = new Timer(100, e->updateTexts());
timer.start();
}
JScrollPane globalScroll = new JScrollPane(actionsListPan);
JLabel titleLabel = new JLabel("Actions de "+personnage.getNom());
globalPan.add(titleLabel,BorderLayout.NORTH);
globalPan.add(globalScroll,BorderLayout.CENTER);
updateTexts();
return globalPan;
}
private void launchAction(Action a) {
if(!a.canBeLaunched())return;
a.launch();
actionButtons.get(a).setEnabled(false);
updateText(a);
updatingActions.add(a);
}
@Override
public YamlMappingBuilder saveToYaml() {
return Yaml.createYamlMappingBuilder().add("personnage", personnage.getNom());
}
public void updateTexts() {
updatingActions.stream().filter(Action::hasFinished).collect(Collectors.toSet())
.stream().forEach(a -> {
actionStatusTexts.get(a).setText(availableText);
actionButtons.get(a).setEnabled(true);
updatingActions.remove(a);
});
updatingActions.forEach(this::updateText);
}
public void updateText(Action a) {
actionStatusTexts.get(a).setText(String.format(waitingTimeText, ParseUtils.dumpTimeLength(a.timeToWaitLeft()), ParseUtils.dumpHourDate(a.dateReset())));
}
}

View File

@ -1,16 +1,23 @@
package com.bernard.murder.view.minel;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Font;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.ListCellRenderer;
import com.bernard.murder.ParseUtils;
import com.amihaiemil.eoyaml.Yaml;
import com.amihaiemil.eoyaml.YamlMapping;
import com.amihaiemil.eoyaml.YamlMappingBuilder;
import com.bernard.murder.game.GameManager;
import com.bernard.murder.model.Inventaire;
import com.bernard.murder.model.Objet;
import com.bernard.murder.view.GlobalUIManager;
import com.bernard.murder.view.minel.objetDnD.ObjetDropTarget;
import com.bernard.murder.view.minel.objetDnD.ObjetTransferHandler;
public class InventaireMinel extends Minel {
@ -19,27 +26,40 @@ public class InventaireMinel extends Minel {
this.inv = inv;
}
public InventaireMinel(GameManager gm, YamlMapping ym) {
this(gm,gm.getInventoryByName(ym.string("inventaire")));
}
JList<Objet> objets;
Inventaire inv;
@Override
public JPanel genContentPane(GlobalUIManager guim) {
public JPanel genContentPane() {
JPanel globalpan = new JPanel(new BorderLayout());
globalpan.setBackground(ParseUtils.randColor());
if(inv.getInventoryName()!=null) {
JLabel invName = new JLabel(inv.getInventoryName());
globalpan.add(invName, BorderLayout.NORTH);
}
JPanel inventaire = new JPanel();
inventaire.setBackground(ParseUtils.randColor());
JButton voler = new JButton("RandomItem");
voler.addActionListener(e -> {
objets.setSelectedIndex((int) (Math.random() * objets.getModel().getSize()));
});
// TODO dragndrop multiple items
objets = new JList<Objet>();
objets.addMouseListener(guim);
objets.setCellRenderer(new ObjetListCellRenderer());
objets.setDragEnabled(true);
objets.setTransferHandler(new ObjetTransferHandler());
updateObjets();
final ObjetDropTarget odt = new ObjetDropTarget(manager, inv, this::updateObjets);
objets.setDropTarget(odt);
globalpan.setDropTarget(odt);
manager.addInventoryUpdateListener(inv, this::updateObjets);
inventaire.add(objets);
@ -50,9 +70,40 @@ public class InventaireMinel extends Minel {
}
private void updateObjets() {
System.out.print("Updating "+inv+" with");
manager.dumpCurrentState();
Objet[] objz = new Objet[inv.getObjects().size()];
objz = inv.getObjects().toArray(objz);
objets.setListData(objz);
}
@Override
public YamlMappingBuilder saveToYaml() {
return Yaml.createYamlMappingBuilder().add("inventaire", inv.getInventoryName());
}
public static class ObjetListCellRenderer extends JLabel implements ListCellRenderer<Objet> {
private static final long serialVersionUID = -7176962839330435585L;
@Override
public Component getListCellRendererComponent(JList<? extends Objet> list, Objet objet, int index,
boolean isSelected, boolean cellHasFocus) {
setText(objet.getNom());
if (isSelected) {
setFont(getFont().deriveFont(Font.BOLD));
setBackground(list.getSelectionBackground());
setForeground(list.getSelectionForeground());
} else {
setFont(getFont().deriveFont(Font.PLAIN));
setBackground(list.getBackground());
setForeground(list.getForeground());
}
return this;
}
}
}

View File

@ -2,8 +2,9 @@ package com.bernard.murder.view.minel;
import javax.swing.JPanel;
import com.amihaiemil.eoyaml.YamlMapping;
import com.amihaiemil.eoyaml.YamlMappingBuilder;
import com.bernard.murder.game.GameManager;
import com.bernard.murder.view.GlobalUIManager;
public abstract class Minel{
@ -15,7 +16,12 @@ public abstract class Minel{
this.manager = manager;
}
public abstract JPanel genContentPane(GlobalUIManager guim);
public Minel(GameManager manager, YamlMapping node) {
this.manager = manager;
}
public abstract JPanel genContentPane();
public abstract YamlMappingBuilder saveToYaml();
}

View File

@ -0,0 +1,143 @@
package com.bernard.murder.view.minel;
import java.awt.BorderLayout;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.event.DocumentEvent;
import com.amihaiemil.eoyaml.Scalar;
import com.amihaiemil.eoyaml.Yaml;
import com.amihaiemil.eoyaml.YamlMapping;
import com.amihaiemil.eoyaml.YamlMappingBuilder;
import com.amihaiemil.eoyaml.YamlNode;
import com.bernard.murder.ParseUtils;
import com.bernard.murder.YamlUtils;
import com.bernard.murder.game.GameManager;
import com.bernard.murder.model.Inventaire;
import com.bernard.murder.model.Objet;
import com.bernard.murder.util.view.SimpleDocumentListener;
public class ObjetSearchMinel extends Minel {
Set<Inventaire> overwatchedInventories;
Map<Objet,Inventaire> objets;
public ObjetSearchMinel(GameManager manager, Set<Inventaire> toOverwatch) {
super(manager);
overwatchedInventories = toOverwatch;
objets = new HashMap<Objet, Inventaire>();
for(Inventaire i : overwatchedInventories) {
i.getObjects().stream().forEach(o -> objets.put(o, i));
manager.addInventoryUpdateListener(i, ()->i.getObjects().stream().forEach(o -> objets.put(o, i)));
}
}
public ObjetSearchMinel(GameManager gm,YamlMapping ym) {
this(gm,
gm.getEveryInventaireByName(
ym.yamlSequence("overwatchedInventories")
.values()
.stream()
.map(YamlNode::asScalar)
.map(Scalar::value)
.collect(Collectors.toSet())
)
);
}
@Override
public JPanel genContentPane() {
JPanel globalPan = new JPanel(new BorderLayout());
JTextField searchField = new JTextField();
searchField.setToolTipText("Objet à chercher");
JList<InventorizedObject> searchResults = new JList<>();
searchField.getDocument().addDocumentListener(new SimpleDocumentListener() {
@Override
public void changedUpdate(DocumentEvent e) {
System.out.println("Updated to "+e.getDocument().toString());
String searchText = searchField.getText();
if(searchText.isBlank()) {
searchResults.setListData(new InventorizedObject[0]);
return;
}
Set<InventorizedObject> startMatch = new HashSet<>();
Set<InventorizedObject> anyMatch = new HashSet<>();
Set<InventorizedObject> subwordMatch = new HashSet<>();
for(Objet o : objets.keySet()) {
System.out.println(o+"->"+searchText);
if(o.getNom().startsWith(searchText))
startMatch.add(new InventorizedObject(o,objets.get(o)));
else if(o.getNom().contains(searchText))
anyMatch.add(new InventorizedObject(o,objets.get(o)));
else if(ParseUtils.isSubWord(o.getNom(), searchText))
subwordMatch.add(new InventorizedObject(o,objets.get(o)));
}
InventorizedObject[] results =
Stream.concat(Stream.concat(
startMatch.stream().sorted((s,v) -> s.objet.getNom().compareToIgnoreCase(v.objet.getNom())),
anyMatch.stream().sorted((s,v) -> s.objet.getNom().compareToIgnoreCase(v.objet.getNom()))),
subwordMatch.stream().sorted((s,v) -> s.objet.getNom().compareToIgnoreCase(v.objet.getNom())))
.toArray(InventorizedObject[]::new);
searchResults.setListData(results);
}
});
globalPan.add(searchField, BorderLayout.NORTH);
globalPan.add(searchResults,BorderLayout.CENTER);
return globalPan;
}
@Override
public YamlMappingBuilder saveToYaml() {
return Yaml.createYamlMappingBuilder().add("overwatchedInventories",
YamlUtils.listToSeqString(overwatchedInventories.stream()
.map(Inventaire::getInventoryName)
.collect(Collectors.toList())));
}
public static class InventorizedObject{
Objet objet;
Inventaire inventaire;
public InventorizedObject(Objet objet, Inventaire inventaire) {
this.objet = objet;
this.inventaire = inventaire;
}
public void changeInventory(Inventaire inventaire) {
this.inventaire = inventaire;
}
@Override
public String toString() {
return objet.getNom()+" ("+inventaire.getInventoryName()+")";
}
}
}

View File

@ -0,0 +1,39 @@
package com.bernard.murder.view.minel;
import javax.swing.JLabel;
import javax.swing.JPanel;
import com.amihaiemil.eoyaml.Yaml;
import com.amihaiemil.eoyaml.YamlMapping;
import com.amihaiemil.eoyaml.YamlMappingBuilder;
import com.bernard.murder.audio.AudioServer;
import com.bernard.murder.game.GameManager;
public class ServeurMinel extends Minel {
AudioServer serveur;
public ServeurMinel(GameManager manager) {
super(manager);
serveur = new AudioServer();
}
public ServeurMinel(GameManager manager,YamlMapping ym) {
super(manager);
serveur = new AudioServer();
}
@Override
public JPanel genContentPane() {
JPanel pan = new JPanel();
JLabel label = new JLabel("Rien pour l'instant");
pan.add(label);
return pan;
}
@Override
public YamlMappingBuilder saveToYaml() {
return Yaml.createYamlMappingBuilder();
}
}

View 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();
}
}

View File

@ -1,37 +1,50 @@
package com.bernard.murder.view.minel;
import java.awt.BorderLayout;
import java.awt.Color;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.border.EmptyBorder;
import com.bernard.murder.ParseUtils;
import com.amihaiemil.eoyaml.Yaml;
import com.amihaiemil.eoyaml.YamlMapping;
import com.amihaiemil.eoyaml.YamlMappingBuilder;
import com.bernard.murder.game.GameManager;
import com.bernard.murder.view.GlobalUIManager;
public class TextPanMinel extends Minel {
String initTexte = "";
JTextArea textArea;
public TextPanMinel(GameManager manager) {
super(manager);
}
@Override
public JPanel genContentPane(GlobalUIManager guim) {
JPanel globalPan = new JPanel(new BorderLayout());
globalPan.setBackground(ParseUtils.randColor());
JTextArea textArea = new JTextArea();
textArea.setBorder(new EmptyBorder(23,23,23,23));
public TextPanMinel(GameManager gm, YamlMapping ym) {
super(gm);
initTexte = ym.string("texte");
}
Color col = ParseUtils.randColor();
textArea.setBackground(col);
textArea.setForeground(ParseUtils.getContrastColor(col));
@Override
public JPanel genContentPane() {
JPanel globalPan = new JPanel(new BorderLayout());
//globalPan.setBackground(ParseUtils.randColor());
textArea = new JTextArea();
textArea.setBorder(new EmptyBorder(23,23,23,23));
textArea.setText(initTexte);
//Color col = ParseUtils.randColor();
//textArea.setBackground(col);
//textArea.setForeground(ParseUtils.getContrastColor(col));
globalPan.add(new JScrollPane(textArea),BorderLayout.CENTER);
return globalPan;
}
@Override
public YamlMappingBuilder saveToYaml() {
return Yaml.createYamlMappingBuilder().add("texte", textArea!=null?textArea.getText():initTexte);
}
}

View File

@ -0,0 +1,17 @@
package com.bernard.murder.view.minel.objetDnD;
import java.awt.dnd.DropTarget;
import java.awt.dnd.DropTargetDropEvent;
public class NotADropTarget extends DropTarget {
private static final long serialVersionUID = -2448755310779755579L;
public NotADropTarget() {}
@Override
public synchronized void drop(DropTargetDropEvent dtde) {
dtde.rejectDrop();
}
}

View File

@ -0,0 +1,45 @@
package com.bernard.murder.view.minel.objetDnD;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DropTarget;
import java.awt.dnd.DropTargetDropEvent;
import java.util.List;
import com.bernard.murder.game.GameManager;
import com.bernard.murder.model.Inventaire;
import com.bernard.murder.model.Objet;
public class ObjetDropTarget extends DropTarget {
private static final long serialVersionUID = 4114342978115089000L;
GameManager manager;
Inventaire toInv;
Runnable[] toUpdate;
public ObjetDropTarget(GameManager manager,Inventaire toInventaire,Runnable... update) {
this.manager = manager;
this.toInv = toInventaire;
this.toUpdate = update;
}
@Override
public synchronized void drop(DropTargetDropEvent e) {
try {
e.acceptDrop(DnDConstants.ACTION_COPY);
@SuppressWarnings("unchecked")
List<Objet> droppedObjets = (List<Objet>) e.getTransferable().getTransferData(ObjetTransferable.objetDataFlavor);
for(Objet o : droppedObjets) {
manager.moveObjet(o,toInv);
}
for(Runnable runnable : toUpdate)
runnable.run();
manager.dumpCurrentState();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}

View File

@ -0,0 +1,34 @@
package com.bernard.murder.view.minel.objetDnD;
import java.awt.datatransfer.Transferable;
import java.util.List;
import javax.swing.JComponent;
import javax.swing.JList;
import javax.swing.TransferHandler;
import com.bernard.murder.model.Objet;
public class ObjetTransferHandler extends TransferHandler {
private static final long serialVersionUID = -8817518488023807932L;
@Override
public int getSourceActions(JComponent c) {
return TransferHandler.MOVE;
}
@Override
protected Transferable createTransferable(JComponent c) {
@SuppressWarnings("unchecked")
JList<Objet> liste = (JList<Objet>) c;
List<Objet> selected = liste.getSelectedValuesList();
ObjetTransferable transferable = new ObjetTransferable(selected);
return transferable;
}
}

View File

@ -0,0 +1,45 @@
package com.bernard.murder.view.minel.objetDnD;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import com.bernard.murder.model.Objet;
public class ObjetTransferable implements Transferable{
private final List<Objet> objets;
private final DataFlavor[] flavors;
public static final DataFlavor objetDataFlavor = new DataFlavor(Objet.class, "fichierMurder");
public ObjetTransferable(Collection<Objet> objets) {
this.objets = Collections.unmodifiableList(
new ArrayList<Objet>(objets));
this.flavors = new DataFlavor[] { ObjetTransferable.objetDataFlavor };
}
@Override
public DataFlavor[] getTransferDataFlavors() {
return flavors;
}
@Override
public boolean isDataFlavorSupported(DataFlavor flavor) {
return Arrays.stream(flavors).anyMatch(f -> f == flavor);
}
@Override
public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
if(isDataFlavorSupported(flavor))
return objets;
else
throw new UnsupportedFlavorException(flavor);
}
}