mirror of
https://github.com/sirjonasxx/G-Earth.git
synced 2024-06-16 08:15:33 +02:00
Compare commits
45 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
8a717ad73f | ||
|
2c5c3f7db8 | ||
|
feb1f2a527 | ||
|
813fda45e5 | ||
|
b19d8baab4 | ||
|
1add63115c | ||
|
03271c344d | ||
|
930f4d7641 | ||
|
8ebd6ac189 | ||
|
e9804afc41 | ||
|
ac9e802d50 | ||
|
e1acccf303 | ||
|
223df57a6a | ||
|
1579bed1ef | ||
|
c7037c0441 | ||
|
df3aabf518 | ||
|
de39613091 | ||
|
f6626d1537 | ||
|
6db7c31bfa | ||
|
76acc8b391 | ||
|
bfc1d3a843 | ||
|
a8559cfdb1 | ||
|
a50fea88f4 | ||
|
a34d16f1cc | ||
|
cb786d4749 | ||
|
3ee8f55766 | ||
|
22f648ec6d | ||
|
ee73ae1d41 | ||
|
8de3d5cdd4 | ||
|
df12a945f4 | ||
|
1b72d600a3 | ||
|
c06c4d41bb | ||
|
150afc9ce1 | ||
|
a868ab512c | ||
|
d96c468103 | ||
|
4c7b924268 | ||
|
661ef48076 | ||
|
413c76915f | ||
|
aec5d6a137 | ||
|
43c15fed3e | ||
|
6a9b1201ac | ||
|
199fbed0dc | ||
|
8a880a13df | ||
|
16749e9e96 | ||
|
d8c5c8ebc0 |
|
@ -10,7 +10,7 @@
|
|||
|
||||
<properties>
|
||||
<javafx.version>1.8</javafx.version>
|
||||
<jettyVersion>9.4.48.v20220622</jettyVersion>
|
||||
<jettyVersion>9.4.51.v20230217</jettyVersion>
|
||||
<logback.version>1.3.5</logback.version>
|
||||
</properties>
|
||||
|
||||
|
@ -209,7 +209,7 @@
|
|||
<dependency>
|
||||
<groupId>org.json</groupId>
|
||||
<artifactId>json</artifactId>
|
||||
<version>20190722</version>
|
||||
<version>20230227</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.fxmisc.richtext</groupId>
|
||||
|
@ -238,14 +238,11 @@
|
|||
<artifactId>maven-artifact</artifactId>
|
||||
<version>3.6.3</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>javax.websocket</groupId>
|
||||
<artifactId>javax.websocket-api</artifactId>
|
||||
<version>1.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-server</artifactId>
|
||||
|
|
|
@ -5,6 +5,7 @@ import gearth.misc.Cacher;
|
|||
import gearth.misc.UpdateChecker;
|
||||
import gearth.misc.listenerpattern.ObservableObject;
|
||||
import gearth.ui.GEarthController;
|
||||
import gearth.ui.GEarthTrayIcon;
|
||||
import gearth.ui.themes.Theme;
|
||||
import gearth.ui.themes.ThemeFactory;
|
||||
import gearth.ui.titlebar.TitleBarConfig;
|
||||
|
@ -41,7 +42,6 @@ public class GEarth extends Application {
|
|||
public void start(Stage primaryStage) throws Exception{
|
||||
main = this;
|
||||
stage = primaryStage;
|
||||
|
||||
FXMLLoader loader = new FXMLLoader(getClass().getResource("/gearth/ui/G-Earth.fxml"));
|
||||
Parent root;
|
||||
try {
|
||||
|
@ -120,7 +120,8 @@ public class GEarth extends Application {
|
|||
stage.getScene().getStylesheets().add(GEarth.class.getResource(String.format("/gearth/ui/themes/%s/styling.css", theme.internalName())).toExternalForm());
|
||||
|
||||
stage.getIcons().clear();
|
||||
stage.getIcons().add(new Image(GEarth.class.getResourceAsStream(String.format("/gearth/ui/themes/%s/logoSmall.png", theme.overridesLogo() ? theme.internalName() : defaultTheme.internalName()))));
|
||||
final Image image = new Image(GEarth.class.getResourceAsStream(String.format("/gearth/ui/themes/%s/logoSmall.png", theme.overridesLogo() ? theme.internalName() : defaultTheme.internalName())));
|
||||
stage.getIcons().add(image);
|
||||
stage.setTitle((theme.overridesTitle() ? theme.title() : defaultTheme.title()) + " " + GEarth.version);
|
||||
|
||||
controller.infoController.img_logo.setImage(new Image(GEarth.class.getResourceAsStream(
|
||||
|
@ -131,7 +132,11 @@ public class GEarth extends Application {
|
|||
)));
|
||||
controller.infoController.version.setText(stage.getTitle());
|
||||
// });
|
||||
GEarthTrayIcon.updateOrCreate(image);
|
||||
}
|
||||
|
||||
public GEarthController getController() {
|
||||
return controller;
|
||||
}
|
||||
|
||||
public static String[] args;
|
||||
|
|
|
@ -169,9 +169,7 @@ public abstract class ExtensionBase extends IExtension {
|
|||
* The application got doubleclicked from the G-Earth interface. Doing something here is optional
|
||||
*/
|
||||
@Override
|
||||
void onClick() {
|
||||
|
||||
}
|
||||
protected void onClick() {}
|
||||
|
||||
@Override
|
||||
protected ExtensionInfo getInfoAnnotations() {
|
||||
|
|
|
@ -67,7 +67,7 @@ public abstract class ExtensionForm extends ExtensionBase {
|
|||
/**
|
||||
* The application got doubleclicked from the G-Earth interface. Doing something here is optional
|
||||
*/
|
||||
public void onClick(){
|
||||
public final void onClick(){
|
||||
Platform.runLater(() -> {
|
||||
primaryStage.show();
|
||||
primaryStage.requestFocus();
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
package gearth.extensions.parsers;
|
||||
|
||||
import gearth.extensions.parsers.stuffdata.IStuffData;
|
||||
import gearth.protocol.HPacket;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class HFloorItem implements IFurni {
|
||||
private int id;
|
||||
|
@ -12,17 +11,15 @@ public class HFloorItem implements IFurni {
|
|||
private HPoint tile;
|
||||
private HDirection facing;
|
||||
|
||||
private int category;
|
||||
|
||||
private int secondsToExpiration;
|
||||
private int usagePolicy;
|
||||
private int ownerId;
|
||||
private String ownerName;
|
||||
private Object[] stuff;
|
||||
private IStuffData stuff;
|
||||
|
||||
private String ignore1;
|
||||
private Integer ignore2;
|
||||
private String ignore3;
|
||||
private String sizeZ;
|
||||
private Integer extra;
|
||||
private String staticClass;
|
||||
|
||||
public HFloorItem(HPacket packet) {
|
||||
id = packet.readInteger();
|
||||
|
@ -34,12 +31,10 @@ public class HFloorItem implements IFurni {
|
|||
|
||||
tile = new HPoint(x, y, Double.parseDouble(packet.readString()));
|
||||
|
||||
ignore1 = packet.readString();
|
||||
ignore2 = packet.readInteger();
|
||||
sizeZ = packet.readString();
|
||||
extra = packet.readInteger();
|
||||
|
||||
category = packet.readInteger();
|
||||
|
||||
stuff = HStuff.readData(packet, category);
|
||||
stuff = IStuffData.read(packet);
|
||||
|
||||
secondsToExpiration = packet.readInteger();
|
||||
usagePolicy = packet.readInteger();
|
||||
|
@ -47,13 +42,11 @@ public class HFloorItem implements IFurni {
|
|||
ownerId = packet.readInteger();
|
||||
|
||||
if (typeId < 0) {
|
||||
ignore3 = packet.readString();
|
||||
staticClass = packet.readString();
|
||||
}
|
||||
else {
|
||||
ignore3 = null;
|
||||
staticClass = null;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void appendToPacket(HPacket packet) {
|
||||
|
@ -76,20 +69,14 @@ public class HFloorItem implements IFurni {
|
|||
packet.appendString(tile.getZ() + "");
|
||||
|
||||
|
||||
// ignore1 = packet.readString();
|
||||
packet.appendString(ignore1);
|
||||
// sizeZ = packet.readString();
|
||||
packet.appendString(sizeZ);
|
||||
|
||||
// ignore2 = packet.readInteger();
|
||||
packet.appendInt(ignore2);
|
||||
// extra = packet.readInteger();
|
||||
packet.appendInt(extra);
|
||||
|
||||
// category = packet.readInteger();
|
||||
packet.appendInt(category);
|
||||
|
||||
|
||||
// stuff = HStuff.readData(packet, category);
|
||||
for (Object object : stuff) {
|
||||
packet.appendObject(object);
|
||||
}
|
||||
// stuff = IStuffData.read(packet);
|
||||
stuff.appendToPacket(packet);
|
||||
|
||||
// secondsToExpiration = packet.readInteger();
|
||||
packet.appendInt(secondsToExpiration);
|
||||
|
@ -102,8 +89,8 @@ public class HFloorItem implements IFurni {
|
|||
|
||||
|
||||
if (typeId < 0) {
|
||||
// ignore3 = packet.readString();
|
||||
packet.appendString(ignore3);
|
||||
// staticClass = packet.readString();
|
||||
packet.appendString(staticClass);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -174,9 +161,9 @@ public class HFloorItem implements IFurni {
|
|||
return secondsToExpiration;
|
||||
}
|
||||
|
||||
public int getCategory() {
|
||||
return category;
|
||||
}
|
||||
// public int getCategory() {
|
||||
// return category;
|
||||
// }
|
||||
|
||||
public HDirection getFacing() {
|
||||
return facing;
|
||||
|
@ -186,7 +173,7 @@ public class HFloorItem implements IFurni {
|
|||
return tile;
|
||||
}
|
||||
|
||||
public Object[] getStuff() {
|
||||
public IStuffData getStuff() {
|
||||
return stuff;
|
||||
}
|
||||
|
||||
|
@ -210,9 +197,9 @@ public class HFloorItem implements IFurni {
|
|||
this.facing = facing;
|
||||
}
|
||||
|
||||
public void setCategory(int category) {
|
||||
this.category = category;
|
||||
}
|
||||
// public void setCategory(int category) {
|
||||
// this.category = category;
|
||||
// }
|
||||
|
||||
public void setSecondsToExpiration(int secondsToExpiration) {
|
||||
this.secondsToExpiration = secondsToExpiration;
|
||||
|
@ -226,7 +213,7 @@ public class HFloorItem implements IFurni {
|
|||
this.ownerId = ownerId;
|
||||
}
|
||||
|
||||
public void setStuff(Object[] stuff) {
|
||||
public void setStuff(IStuffData stuff) {
|
||||
this.stuff = stuff;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package gearth.extensions.parsers;
|
||||
|
||||
import gearth.extensions.parsers.stuffdata.IStuffData;
|
||||
import gearth.protocol.HPacket;
|
||||
|
||||
public class HInventoryItem {
|
||||
|
@ -8,8 +9,7 @@ public class HInventoryItem {
|
|||
private int id;
|
||||
private int typeId;
|
||||
private HSpecialType specialType;
|
||||
private int category;
|
||||
private Object[] stuff;
|
||||
private IStuffData stuff;
|
||||
private boolean recyclable;
|
||||
private boolean tradeable;
|
||||
private boolean groupable;
|
||||
|
@ -27,8 +27,7 @@ public class HInventoryItem {
|
|||
id = packet.readInteger();
|
||||
typeId = packet.readInteger();
|
||||
specialType = HSpecialType.fromId(packet.readInteger());
|
||||
category = packet.readInteger();
|
||||
stuff = HStuff.readData(packet, category);
|
||||
stuff = IStuffData.read(packet);
|
||||
recyclable = packet.readBoolean();
|
||||
tradeable = packet.readBoolean();
|
||||
groupable = packet.readBoolean();
|
||||
|
@ -49,11 +48,7 @@ public class HInventoryItem {
|
|||
packet.appendInt(id);
|
||||
packet.appendInt(typeId);
|
||||
packet.appendInt(specialType.getId());
|
||||
packet.appendInt(category);
|
||||
|
||||
for (Object object : stuff) {
|
||||
packet.appendObject(object);
|
||||
}
|
||||
stuff.appendToPacket(packet);
|
||||
|
||||
packet.appendBoolean(recyclable);
|
||||
packet.appendBoolean(tradeable);
|
||||
|
@ -133,19 +128,11 @@ public class HInventoryItem {
|
|||
this.typeId = typeId;
|
||||
}
|
||||
|
||||
public int getCategory() {
|
||||
return category;
|
||||
}
|
||||
|
||||
public void setCategory(int category) {
|
||||
this.category = category;
|
||||
}
|
||||
|
||||
public Object[] getStuff() {
|
||||
public IStuffData getStuff() {
|
||||
return stuff;
|
||||
}
|
||||
|
||||
public void setStuff(Object[] stuff) {
|
||||
public void setStuff(IStuffData stuff) {
|
||||
this.stuff = stuff;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,91 +0,0 @@
|
|||
package gearth.extensions.parsers;
|
||||
|
||||
import gearth.protocol.HPacket;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class HStuff {
|
||||
|
||||
public static Object[] readData(HPacket packet, int category) {
|
||||
List<Object> values = new ArrayList<>();
|
||||
switch (category & 0xFF)
|
||||
{
|
||||
case 0: /* LegacyStuffData */ {
|
||||
values.add(packet.readString());
|
||||
break;
|
||||
}
|
||||
case 1: /* MapStuffData */ {
|
||||
int count = packet.readInteger();
|
||||
values.add(count);
|
||||
|
||||
for (int j = 0; j < count; j++)
|
||||
{
|
||||
values.add(packet.readString());
|
||||
values.add(packet.readString());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 2: /* StringArrayStuffData */ {
|
||||
int count = packet.readInteger();
|
||||
values.add(count);
|
||||
|
||||
for (int j = 0; j < count; j++)
|
||||
{
|
||||
values.add(packet.readString());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 3: /* VoteResultStuffData */ {
|
||||
values.add(packet.readString());
|
||||
values.add(packet.readInteger());
|
||||
break;
|
||||
}
|
||||
case 5: /* IntArrayStuffData */ {
|
||||
int count = packet.readInteger();
|
||||
values.add(count);
|
||||
|
||||
for (int j = 0; j < count; j++)
|
||||
{
|
||||
values.add(packet.readInteger());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 6: /* HighScoreStuffData */ {
|
||||
values.add(packet.readString());
|
||||
values.add(packet.readInteger());
|
||||
values.add(packet.readInteger());
|
||||
|
||||
int count = packet.readInteger();
|
||||
values.add(count);
|
||||
|
||||
for (int j = 0; j < count; j++)
|
||||
{
|
||||
int score = packet.readInteger();
|
||||
values.add(score);
|
||||
|
||||
int subCount = packet.readInteger();
|
||||
values.add(subCount);
|
||||
|
||||
for (int k = 0; k < subCount; k++)
|
||||
{
|
||||
values.add(packet.readString());
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 7: /* CrackableStuffData */ {
|
||||
values.add(packet.readString());
|
||||
values.add(packet.readInteger());
|
||||
values.add(packet.readInteger());
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ((category & 0xFF00 & 0x100) > 0) {
|
||||
values.add(packet.readInteger());
|
||||
values.add(packet.readInteger());
|
||||
}
|
||||
return values.toArray();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,173 @@
|
|||
package gearth.extensions.parsers.stuffdata;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.UnaryOperator;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* Wrapper class to make IntArrayStuffData and StringArrayStuffData behave like a List
|
||||
* @param <T> Value class
|
||||
*/
|
||||
public class ArrayStuffData<T> extends StuffDataBase implements List<T> {
|
||||
protected List<T> values = new ArrayList<>();
|
||||
|
||||
public ArrayStuffData() {
|
||||
super();
|
||||
}
|
||||
|
||||
public ArrayStuffData(int uniqueSerialNumber, int uniqueSerialSize) {
|
||||
super(uniqueSerialNumber, uniqueSerialSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return values.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return values.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
return values.contains(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<T> iterator() {
|
||||
return values.iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forEach(Consumer<? super T> action) {
|
||||
values.forEach(action);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] toArray() {
|
||||
return values.toArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T1> T1[] toArray(T1[] a) {
|
||||
return values.toArray(a);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(T t) {
|
||||
return values.add(t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object o) {
|
||||
return values.remove(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsAll(Collection<?> c) {
|
||||
return values.containsAll(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(Collection<? extends T> c) {
|
||||
return values.addAll(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(int index, Collection<? extends T> c) {
|
||||
return values.addAll(index, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeAll(Collection<?> c) {
|
||||
return values.removeAll(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeIf(Predicate<? super T> filter) {
|
||||
return values.removeIf(filter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean retainAll(Collection<?> c) {
|
||||
return values.retainAll(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void replaceAll(UnaryOperator<T> operator) {
|
||||
values.replaceAll(operator);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sort(Comparator<? super T> c) {
|
||||
values.sort(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
values.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T get(int index) {
|
||||
return values.get(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T set(int index, T element) {
|
||||
return values.set(index, element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(int index, T element) {
|
||||
values.add(index, element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T remove(int index) {
|
||||
return values.remove(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int indexOf(Object o) {
|
||||
return values.indexOf(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int lastIndexOf(Object o) {
|
||||
return values.lastIndexOf(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListIterator<T> listIterator() {
|
||||
return values.listIterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListIterator<T> listIterator(int index) {
|
||||
return values.listIterator(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<T> subList(int fromIndex, int toIndex) {
|
||||
return values.subList(fromIndex, toIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Spliterator<T> spliterator() {
|
||||
return values.spliterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<T> stream() {
|
||||
return values.stream();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<T> parallelStream() {
|
||||
return values.parallelStream();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
package gearth.extensions.parsers.stuffdata;
|
||||
|
||||
import gearth.protocol.HPacket;
|
||||
|
||||
public class CrackableStuffData extends StuffDataBase {
|
||||
public final static int IDENTIFIER = 7;
|
||||
|
||||
private String legacyString = "";
|
||||
private int hits = 0;
|
||||
private int target = 0;
|
||||
|
||||
protected CrackableStuffData() {}
|
||||
|
||||
public CrackableStuffData(String legacyString, int hits, int target) {
|
||||
super();
|
||||
this.legacyString = legacyString == null ? "" : legacyString;
|
||||
this.hits = hits;
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
|
||||
public CrackableStuffData(int uniqueSerialNumber, int uniqueSerialSize, String legacyString, int hits, int target) {
|
||||
super(uniqueSerialNumber, uniqueSerialSize);
|
||||
this.legacyString = legacyString == null ? "" : legacyString;
|
||||
this.hits = hits;
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initialize(HPacket packet) {
|
||||
this.legacyString = packet.readString();
|
||||
this.hits = packet.readInteger();
|
||||
this.target = packet.readInteger();
|
||||
super.initialize(packet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendToPacket(HPacket packet) {
|
||||
packet.appendInt(IDENTIFIER | this.getFlags());
|
||||
packet.appendObjects(
|
||||
this.legacyString,
|
||||
this.hits,
|
||||
this.target
|
||||
);
|
||||
super.appendToPacket(packet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLegacyString() {
|
||||
return this.legacyString;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLegacyString(String legacyString) {
|
||||
this.legacyString = legacyString;
|
||||
}
|
||||
|
||||
public int getHits() {
|
||||
return this.hits;
|
||||
}
|
||||
|
||||
public void setHits(int hits) {
|
||||
this.hits = hits;
|
||||
}
|
||||
|
||||
public int getTarget() {
|
||||
return this.target;
|
||||
}
|
||||
|
||||
public void setTarget(int target) {
|
||||
this.target = target;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package gearth.extensions.parsers.stuffdata;
|
||||
|
||||
import gearth.protocol.HPacket;
|
||||
|
||||
public class EmptyStuffData extends StuffDataBase {
|
||||
public final static int IDENTIFIER = 4;
|
||||
|
||||
public EmptyStuffData() {
|
||||
super();
|
||||
}
|
||||
|
||||
public EmptyStuffData(int uniqueSerialNumber, int uniqueSerialSize) {
|
||||
super(uniqueSerialNumber, uniqueSerialSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initialize(HPacket packet) {
|
||||
super.initialize(packet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendToPacket(HPacket packet) {
|
||||
packet.appendInt(IDENTIFIER | this.getFlags());
|
||||
super.appendToPacket(packet);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
package gearth.extensions.parsers.stuffdata;
|
||||
|
||||
import gearth.protocol.HPacket;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
public class HighScoreData {
|
||||
private int score;
|
||||
private String[] users;
|
||||
|
||||
protected HighScoreData(HPacket packet) {
|
||||
this.score = packet.readInteger();
|
||||
int size = packet.readInteger();
|
||||
this.users = new String[size];
|
||||
for (int i = 0; i < size; i++) {
|
||||
this.users[i] = packet.readString();
|
||||
}
|
||||
}
|
||||
|
||||
public HighScoreData(int score, String... users) {
|
||||
super();
|
||||
this.score = score;
|
||||
this.users = Arrays.stream(users).filter(Objects::nonNull).toArray(String[]::new);
|
||||
}
|
||||
|
||||
protected void appendToPacket(HPacket packet) {
|
||||
packet.appendInt(this.score);
|
||||
packet.appendInt(this.users.length);
|
||||
for (String user : this.users) {
|
||||
packet.appendString(user);
|
||||
}
|
||||
}
|
||||
|
||||
public int getScore() {
|
||||
return this.score;
|
||||
}
|
||||
|
||||
public void setScore(int score) {
|
||||
this.score = score;
|
||||
}
|
||||
|
||||
public String[] getUsers() {
|
||||
return this.users.clone();
|
||||
}
|
||||
|
||||
public void setUsers(String[] users) {
|
||||
this.users = Arrays
|
||||
.stream(users == null ? new String[0] : users)
|
||||
.filter(Objects::nonNull)
|
||||
.toArray(String[]::new);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
package gearth.extensions.parsers.stuffdata;
|
||||
|
||||
import gearth.protocol.HPacket;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
public class HighScoreStuffData extends StuffDataBase {
|
||||
public final static int IDENTIFIER = 6;
|
||||
|
||||
private String legacyString = "";
|
||||
// ['perteam', 'mostwins', 'classic', 'fastesttime', 'longesttime']
|
||||
private int scoreType = 0;
|
||||
// ['alltime', 'daily', 'weekly', 'monthly']
|
||||
private int clearType = 0;
|
||||
private HighScoreData[] entries = {};
|
||||
|
||||
protected HighScoreStuffData() {}
|
||||
|
||||
public HighScoreStuffData(String legacyString, int scoreType, int clearType, HighScoreData... entries) {
|
||||
super();
|
||||
this.legacyString = legacyString == null ? "" : legacyString;
|
||||
this.scoreType = scoreType;
|
||||
this.clearType = clearType;
|
||||
this.entries = Arrays.stream(entries).filter(Objects::nonNull).toArray(HighScoreData[]::new);
|
||||
}
|
||||
|
||||
public HighScoreStuffData(int uniqueSerialNumber, int uniqueSerialSize, String legacyString, int scoreType, int clearType, HighScoreData... entries) {
|
||||
super(uniqueSerialNumber, uniqueSerialSize);
|
||||
this.legacyString = legacyString == null ? "" : legacyString;
|
||||
this.scoreType = scoreType;
|
||||
this.clearType = clearType;
|
||||
this.entries = Arrays.stream(entries).filter(Objects::nonNull).toArray(HighScoreData[]::new);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initialize(HPacket packet) {
|
||||
this.legacyString = packet.readString();
|
||||
this.scoreType = packet.readInteger();
|
||||
this.clearType = packet.readInteger();
|
||||
|
||||
int size = packet.readInteger();
|
||||
this.entries = new HighScoreData[size];
|
||||
for (int i = 0; i < size; i++) {
|
||||
this.entries[i] = new HighScoreData(packet);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendToPacket(HPacket packet) {
|
||||
packet.appendInt(IDENTIFIER | this.getFlags());
|
||||
packet.appendObjects(
|
||||
this.legacyString,
|
||||
this.scoreType,
|
||||
this.clearType,
|
||||
this.entries.length
|
||||
);
|
||||
for (HighScoreData entry : this.entries) {
|
||||
entry.appendToPacket(packet);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLegacyString() {
|
||||
return this.legacyString;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLegacyString(String legacyString) {
|
||||
this.legacyString = legacyString;
|
||||
}
|
||||
|
||||
public int getScoreType() {
|
||||
return this.scoreType;
|
||||
}
|
||||
|
||||
public void setScoreType(int scoreType) {
|
||||
this.scoreType = scoreType;
|
||||
}
|
||||
|
||||
public int getClearType() {
|
||||
return this.clearType;
|
||||
}
|
||||
|
||||
public void setClearType(int clearType) {
|
||||
this.clearType = clearType;
|
||||
}
|
||||
|
||||
public HighScoreData[] getEntries() {
|
||||
return this.entries.clone();
|
||||
}
|
||||
|
||||
public void setEntries(HighScoreData[] entries) {
|
||||
this.entries = Arrays
|
||||
.stream(entries == null ? new HighScoreData[0] : entries)
|
||||
.filter(Objects::nonNull)
|
||||
.toArray(HighScoreData[]::new);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
package gearth.extensions.parsers.stuffdata;
|
||||
|
||||
import gearth.protocol.HPacket;
|
||||
|
||||
public interface IStuffData {
|
||||
static IStuffData read(HPacket packet) {
|
||||
int a = packet.readInteger();
|
||||
StuffDataBase stuffData = null;
|
||||
|
||||
switch (a & 255) {
|
||||
case LegacyStuffData.IDENTIFIER:
|
||||
stuffData = new LegacyStuffData();
|
||||
break;
|
||||
case MapStuffData.IDENTIFIER:
|
||||
stuffData = new MapStuffData();
|
||||
break;
|
||||
case StringArrayStuffData.IDENTIFIER:
|
||||
stuffData = new StringArrayStuffData();
|
||||
break;
|
||||
case VoteResultStuffData.IDENTIFIER:
|
||||
stuffData = new VoteResultStuffData();
|
||||
break;
|
||||
case EmptyStuffData.IDENTIFIER:
|
||||
stuffData = new EmptyStuffData();
|
||||
break;
|
||||
case IntArrayStuffData.IDENTIFIER:
|
||||
stuffData = new IntArrayStuffData();
|
||||
break;
|
||||
case HighScoreStuffData.IDENTIFIER:
|
||||
stuffData = new HighScoreStuffData();
|
||||
break;
|
||||
case CrackableStuffData.IDENTIFIER:
|
||||
stuffData = new CrackableStuffData();
|
||||
break;
|
||||
}
|
||||
|
||||
if (stuffData != null) {
|
||||
stuffData.setFlags(a & 65280);
|
||||
stuffData.initialize(packet);
|
||||
} else {
|
||||
throw new RuntimeException("Unknown stuffdata type");
|
||||
}
|
||||
|
||||
return stuffData;
|
||||
}
|
||||
|
||||
void appendToPacket(HPacket packet);
|
||||
|
||||
String getLegacyString();
|
||||
void setLegacyString(String legacyString);
|
||||
|
||||
void setFlags(int flags);
|
||||
int getFlags();
|
||||
|
||||
int getUniqueSerialNumber();
|
||||
int getUniqueSerialSize();
|
||||
void setUniqueSerialNumber(int uniqueSerialNumber);
|
||||
void setUniqueSerialSize(int uniqueSerialSize);
|
||||
|
||||
int getRarityLevel();
|
||||
|
||||
int getState();
|
||||
void setState(int state);
|
||||
|
||||
String getJSONValue(String key);
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
package gearth.extensions.parsers.stuffdata;
|
||||
|
||||
import gearth.protocol.HPacket;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
// 5
|
||||
public class IntArrayStuffData extends ArrayStuffData<Integer> {
|
||||
public final static int IDENTIFIER = 5;
|
||||
|
||||
protected IntArrayStuffData() {}
|
||||
|
||||
public IntArrayStuffData(Integer... values) {
|
||||
super();
|
||||
this.values = Arrays.asList(values);
|
||||
}
|
||||
|
||||
public IntArrayStuffData(int uniqueSerialNumber, int uniqueSerialSize, Integer... values) {
|
||||
super(uniqueSerialNumber, uniqueSerialSize);
|
||||
this.values = Arrays.asList(values);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initialize(HPacket packet) {
|
||||
int size = packet.readInteger();
|
||||
this.clear();
|
||||
for (int i = 0; i < size; i++) {
|
||||
this.add(packet.readInteger());
|
||||
}
|
||||
super.initialize(packet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendToPacket(HPacket packet) {
|
||||
packet.appendInt(IDENTIFIER | this.getFlags());
|
||||
packet.appendInt(this.size());
|
||||
for (int i : this) {
|
||||
packet.appendInt(i);
|
||||
}
|
||||
super.appendToPacket(packet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLegacyString() {
|
||||
return this.size() > 0 ? String.valueOf(this.get(0)) : "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLegacyString(String legacyString) {
|
||||
if (this.size() > 0)
|
||||
this.set(0, Integer.parseInt(legacyString));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
package gearth.extensions.parsers.stuffdata;
|
||||
|
||||
import gearth.protocol.HPacket;
|
||||
|
||||
public class LegacyStuffData extends StuffDataBase {
|
||||
public final static int IDENTIFIER = 0;
|
||||
|
||||
private String legacyString;
|
||||
|
||||
protected LegacyStuffData() {}
|
||||
|
||||
public LegacyStuffData(String legacyString) {
|
||||
this.legacyString = legacyString == null ? "" : legacyString;
|
||||
}
|
||||
|
||||
public LegacyStuffData(int uniqueSerialNumber, int uniqueSerialSize, String legacyString) {
|
||||
super(uniqueSerialNumber, uniqueSerialSize);
|
||||
this.legacyString = legacyString == null ? "" : legacyString;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initialize(HPacket packet) {
|
||||
this.legacyString = packet.readString();
|
||||
super.initialize(packet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendToPacket(HPacket packet) {
|
||||
packet.appendInt(IDENTIFIER | this.getFlags());
|
||||
packet.appendString(this.legacyString);
|
||||
super.appendToPacket(packet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLegacyString() {
|
||||
return this.legacyString;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLegacyString(String legacyString) {
|
||||
this.legacyString = legacyString;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,177 @@
|
|||
package gearth.extensions.parsers.stuffdata;
|
||||
|
||||
import gearth.protocol.HPacket;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class MapStuffData extends StuffDataBase implements Map<String, String> {
|
||||
public final static int IDENTIFIER = 1;
|
||||
|
||||
private Map<String, String> map = new HashMap<>();
|
||||
|
||||
protected MapStuffData() {}
|
||||
|
||||
public MapStuffData(HashMap<String, String> map) {
|
||||
this.map = map == null ? new HashMap<>() : map.entrySet().stream().filter(e -> e.getValue() != null).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (x, y) -> y, HashMap::new));
|
||||
}
|
||||
|
||||
public MapStuffData(int uniqueSerialNumber, int uniqueSerialSize, HashMap<String, String> map) {
|
||||
super(uniqueSerialNumber, uniqueSerialSize);
|
||||
this.map = map == null ? new HashMap<>() : map.entrySet().stream().filter(e -> e.getValue() != null).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (x, y) -> y, HashMap::new));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initialize(HPacket packet) {
|
||||
int size = packet.readInteger();
|
||||
this.clear();
|
||||
for (int i = 0; i < size; i++) {
|
||||
this.put(packet.readString(), packet.readString());
|
||||
}
|
||||
super.initialize(packet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendToPacket(HPacket packet) {
|
||||
packet.appendInt(IDENTIFIER | this.getFlags());
|
||||
packet.appendInt(this.size());
|
||||
for (Entry<String, String> entry : this.entrySet()) {
|
||||
packet.appendObjects(
|
||||
entry.getKey(),
|
||||
entry.getValue() == null ? "" : entry.getValue()
|
||||
);
|
||||
}
|
||||
super.appendToPacket(packet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLegacyString() {
|
||||
return this.getOrDefault("state", "");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLegacyString(String legacyString) {
|
||||
this.put("state", legacyString == null ? "" : legacyString);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return this.map.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return this.map.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(Object key) {
|
||||
return this.map.containsKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(Object value) {
|
||||
return this.map.containsValue(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String get(Object key) {
|
||||
return this.map.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String put(String key, String value) {
|
||||
return this.map.put(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String remove(Object key) {
|
||||
return this.map.remove(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(Map<? extends String, ? extends String> m) {
|
||||
this.map.putAll(m);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
this.map.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> keySet() {
|
||||
return this.map.keySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> values() {
|
||||
return this.map.values();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Entry<String, String>> entrySet() {
|
||||
return this.map.entrySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOrDefault(Object key, String defaultValue) {
|
||||
return this.map.getOrDefault(key, defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forEach(BiConsumer<? super String, ? super String> action) {
|
||||
this.map.forEach(action);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void replaceAll(BiFunction<? super String, ? super String, ? extends String> function) {
|
||||
this.map.replaceAll(function);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String putIfAbsent(String key, String value) {
|
||||
return this.map.putIfAbsent(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object key, Object value) {
|
||||
return this.map.remove(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean replace(String key, String oldValue, String newValue) {
|
||||
return this.map.replace(key, oldValue, newValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String replace(String key, String value) {
|
||||
return this.map.replace(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String computeIfAbsent(String key, Function<? super String, ? extends String> mappingFunction) {
|
||||
return this.map.computeIfAbsent(key, mappingFunction);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String computeIfPresent(String key, BiFunction<? super String, ? super String, ? extends String> remappingFunction) {
|
||||
return this.map.computeIfPresent(key, remappingFunction);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String compute(String key, BiFunction<? super String, ? super String, ? extends String> remappingFunction) {
|
||||
return this.map.compute(key, remappingFunction);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String merge(String key, String value, BiFunction<? super String, ? super String, ? extends String> remappingFunction) {
|
||||
return this.map.merge(key, value, remappingFunction);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
package gearth.extensions.parsers.stuffdata;
|
||||
|
||||
import gearth.protocol.HPacket;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
// 2
|
||||
public class StringArrayStuffData extends ArrayStuffData<String> {
|
||||
public final static int IDENTIFIER = 2;
|
||||
|
||||
protected StringArrayStuffData() {}
|
||||
|
||||
public StringArrayStuffData(String... array) {
|
||||
this.values = Arrays.stream(array).filter(Objects::nonNull).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public StringArrayStuffData(int uniqueSerialNumber, int uniqueSerialSize, String... array) {
|
||||
super(uniqueSerialNumber, uniqueSerialSize);
|
||||
this.values = Arrays.stream(array).filter(Objects::nonNull).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initialize(HPacket packet) {
|
||||
int size = packet.readInteger();
|
||||
this.clear();
|
||||
for (int i = 0; i < size; i++) {
|
||||
this.add(packet.readString());
|
||||
}
|
||||
super.initialize(packet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendToPacket(HPacket packet) {
|
||||
packet.appendInt(IDENTIFIER | this.getFlags());
|
||||
packet.appendInt(this.size());
|
||||
for (String s : this) {
|
||||
packet.appendString(s);
|
||||
}
|
||||
super.appendToPacket(packet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLegacyString() {
|
||||
return this.size() > 0 ? this.get(0) : "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLegacyString(String legacyString) {
|
||||
if (this.size() > 0) {
|
||||
this.set(0, legacyString == null ? "" : legacyString);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
package gearth.extensions.parsers.stuffdata;
|
||||
|
||||
import gearth.protocol.HPacket;
|
||||
import org.json.JSONObject;
|
||||
|
||||
public abstract class StuffDataBase implements IStuffData {
|
||||
private int flags = 0;
|
||||
private int uniqueSerialNumber = 0;
|
||||
private int uniqueSerialSize = 0;
|
||||
|
||||
protected StuffDataBase() {}
|
||||
|
||||
protected StuffDataBase(int uniqueSerialNumber, int uniqueSerialSize) {
|
||||
this.uniqueSerialNumber = uniqueSerialNumber;
|
||||
this.uniqueSerialSize = uniqueSerialSize;
|
||||
flags = 256;
|
||||
}
|
||||
|
||||
protected void initialize(HPacket packet) {
|
||||
if ((flags & 256) > 0) {
|
||||
this.uniqueSerialNumber = packet.readInteger();
|
||||
this.uniqueSerialSize = packet.readInteger();
|
||||
}
|
||||
}
|
||||
|
||||
public void appendToPacket(HPacket packet) {
|
||||
if ((flags & 256) > 0) {
|
||||
packet.appendInt(this.uniqueSerialNumber);
|
||||
packet.appendInt(this.uniqueSerialSize);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLegacyString() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLegacyString(String legacyString) {}
|
||||
|
||||
@Override
|
||||
public final void setFlags(int flags) {
|
||||
this.flags = flags;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int getFlags() {
|
||||
return this.flags;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int getUniqueSerialNumber() {
|
||||
return this.uniqueSerialNumber;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int getUniqueSerialSize() {
|
||||
return this.uniqueSerialSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setUniqueSerialNumber(int uniqueSerialNumber) {
|
||||
this.uniqueSerialNumber = uniqueSerialNumber;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setUniqueSerialSize(int uniqueSerialSize) {
|
||||
this.uniqueSerialSize = uniqueSerialSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRarityLevel() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int getState() {
|
||||
try {
|
||||
return Integer.parseInt(getLegacyString());
|
||||
} catch (Exception e) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setState(int state) {
|
||||
setLegacyString(String.valueOf(state));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getJSONValue(String key) {
|
||||
try {
|
||||
return new JSONObject(getLegacyString()).getString(key);
|
||||
} catch (Exception e) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
package gearth.extensions.parsers.stuffdata;
|
||||
|
||||
import gearth.protocol.HPacket;
|
||||
|
||||
public class VoteResultStuffData extends StuffDataBase {
|
||||
public static final int IDENTIFIER = 3;
|
||||
|
||||
private String legacyString = "";
|
||||
private int result = 0;
|
||||
|
||||
protected VoteResultStuffData() {}
|
||||
|
||||
public VoteResultStuffData(String legacyString, int result) {
|
||||
this.legacyString = legacyString == null ? "" : legacyString;
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
public VoteResultStuffData(int uniqueSerialNumber, int uniqueSerialSize, String legacyString, int result) {
|
||||
super(uniqueSerialNumber, uniqueSerialSize);
|
||||
this.legacyString = legacyString == null ? "" : legacyString;
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initialize(HPacket packet) {
|
||||
this.legacyString = packet.readString();
|
||||
this.result = packet.readInteger();
|
||||
super.initialize(packet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendToPacket(HPacket packet) {
|
||||
packet.appendInt(IDENTIFIER | this.getFlags());
|
||||
packet.appendObjects(
|
||||
this.legacyString,
|
||||
this.result
|
||||
);
|
||||
super.appendToPacket(packet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLegacyString() {
|
||||
return this.legacyString;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLegacyString(String legacyString) {
|
||||
this.legacyString = legacyString == null ? "" : legacyString;
|
||||
}
|
||||
|
||||
public int getResult() {
|
||||
return this.result;
|
||||
}
|
||||
|
||||
public void setResult(int result) {
|
||||
this.result = result;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
package gearth.protocol.connection.proxy.nitro;
|
||||
|
||||
import gearth.protocol.HMessage;
|
||||
import gearth.protocol.connection.HState;
|
||||
import gearth.protocol.connection.HStateSetter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class NitroConnectionState {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(NitroConnectionState.class);
|
||||
|
||||
private final HStateSetter stateSetter;
|
||||
|
||||
private boolean aborting;
|
||||
private boolean toServer;
|
||||
private boolean toClient;
|
||||
|
||||
public NitroConnectionState(HStateSetter stateSetter) {
|
||||
this.stateSetter = stateSetter;
|
||||
}
|
||||
|
||||
public void setConnected(HMessage.Direction direction) {
|
||||
if (direction == HMessage.Direction.TOCLIENT) {
|
||||
this.toClient = true;
|
||||
} else if (direction == HMessage.Direction.TOSERVER) {
|
||||
this.toServer = true;
|
||||
}
|
||||
|
||||
this.checkConnected();
|
||||
}
|
||||
|
||||
public boolean isConnected() {
|
||||
if (this.aborting) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!this.toClient) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!this.toServer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void checkConnected() {
|
||||
if (!this.isConnected()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.stateSetter.setState(HState.CONNECTED);
|
||||
|
||||
logger.info("Connected");
|
||||
}
|
||||
|
||||
public void setAborting() {
|
||||
this.aborting = true;
|
||||
this.stateSetter.setState(HState.ABORTING);
|
||||
|
||||
logger.info("Aborting");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package gearth.protocol.connection.proxy.nitro;
|
||||
|
||||
import gearth.protocol.packethandler.nitro.NitroPacketHandler;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Queue;
|
||||
|
||||
public class NitroPacketQueue {
|
||||
|
||||
private final NitroPacketHandler packetHandler;
|
||||
private final Queue<byte[]> packets;
|
||||
|
||||
public NitroPacketQueue(NitroPacketHandler packetHandler) {
|
||||
this.packetHandler = packetHandler;
|
||||
this.packets = new LinkedList<>();
|
||||
}
|
||||
|
||||
public void enqueue(byte[] b) {
|
||||
this.packets.add(b);
|
||||
}
|
||||
|
||||
public synchronized void flush() throws IOException {
|
||||
while (!this.packets.isEmpty()) {
|
||||
this.packetHandler.act(this.packets.remove());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
package gearth.protocol.connection.proxy.nitro.websocket;
|
||||
|
||||
import javax.websocket.Session;
|
||||
import org.eclipse.jetty.websocket.api.Session;
|
||||
|
||||
public interface NitroSession {
|
||||
|
||||
|
|
|
@ -2,8 +2,11 @@ package gearth.protocol.connection.proxy.nitro.websocket;
|
|||
|
||||
import gearth.protocol.HConnection;
|
||||
import gearth.protocol.HMessage;
|
||||
import gearth.protocol.StateChangeListener;
|
||||
import gearth.protocol.connection.*;
|
||||
import gearth.protocol.connection.proxy.nitro.NitroConnectionState;
|
||||
import gearth.protocol.connection.proxy.nitro.NitroConstants;
|
||||
import gearth.protocol.connection.proxy.nitro.NitroPacketQueue;
|
||||
import gearth.protocol.connection.proxy.nitro.NitroProxyProvider;
|
||||
import gearth.protocol.packethandler.nitro.NitroPacketHandler;
|
||||
import org.eclipse.jetty.websocket.jsr356.JsrSession;
|
||||
|
@ -25,22 +28,24 @@ public class NitroWebsocketClient implements NitroSession {
|
|||
private static final Logger logger = LoggerFactory.getLogger(NitroWebsocketClient.class);
|
||||
|
||||
private final HProxySetter proxySetter;
|
||||
private final HStateSetter stateSetter;
|
||||
private final HConnection connection;
|
||||
private final NitroConnectionState state;
|
||||
private final NitroProxyProvider proxyProvider;
|
||||
private final NitroWebsocketServer server;
|
||||
private final NitroPacketHandler packetHandler;
|
||||
private final NitroPacketQueue packetQueue;
|
||||
private final AtomicBoolean shutdownLock;
|
||||
|
||||
private JsrSession activeSession = null;
|
||||
|
||||
public NitroWebsocketClient(HProxySetter proxySetter, HStateSetter stateSetter, HConnection connection, NitroProxyProvider proxyProvider) {
|
||||
this.proxySetter = proxySetter;
|
||||
this.stateSetter = stateSetter;
|
||||
this.connection = connection;
|
||||
this.state = new NitroConnectionState(stateSetter);
|
||||
this.proxyProvider = proxyProvider;
|
||||
this.server = new NitroWebsocketServer(connection, this);
|
||||
this.server = new NitroWebsocketServer(connection, this, this.state);
|
||||
this.packetHandler = new NitroPacketHandler(HMessage.Direction.TOSERVER, server, connection.getExtensionHandler(), connection.getTrafficObservables());
|
||||
this.packetQueue = new NitroPacketQueue(this.packetHandler);
|
||||
this.shutdownLock = new AtomicBoolean();
|
||||
}
|
||||
|
||||
|
@ -48,8 +53,27 @@ public class NitroWebsocketClient implements NitroSession {
|
|||
public void onOpen(Session session) throws Exception {
|
||||
logger.info("WebSocket connection accepted");
|
||||
|
||||
// Setup state change listener
|
||||
connection.getStateObservable().addListener(new StateChangeListener() {
|
||||
@Override
|
||||
public void stateChanged(HState oldState, HState newState) {
|
||||
// Clean up when we don't need it anymore.
|
||||
if ((oldState == HState.WAITING_FOR_CLIENT || newState == HState.NOT_CONNECTED) || newState == HState.ABORTING) {
|
||||
connection.getStateObservable().removeListener(this);
|
||||
}
|
||||
|
||||
// Process queue when connected.
|
||||
try {
|
||||
packetQueue.flush();
|
||||
} catch (IOException e) {
|
||||
logger.error("Failed to flush packet queue in state change listener", e);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
activeSession = (JsrSession) session;
|
||||
activeSession.setMaxBinaryMessageBufferSize(NitroConstants.WEBSOCKET_BUFFER_SIZE);
|
||||
activeSession.getPolicy().setMaxBinaryMessageSize(NitroConstants.WEBSOCKET_BUFFER_SIZE);
|
||||
activeSession.getPolicy().setMaxTextMessageSize(NitroConstants.WEBSOCKET_BUFFER_SIZE);
|
||||
|
||||
// Set proper headers to spoof being a real client.
|
||||
final Map<String, List<String>> headers = new HashMap<>(activeSession.getUpgradeRequest().getHeaders());
|
||||
|
@ -71,12 +95,21 @@ public class NitroWebsocketClient implements NitroSession {
|
|||
);
|
||||
|
||||
proxySetter.setProxy(proxy);
|
||||
stateSetter.setState(HState.CONNECTED);
|
||||
state.setConnected(HMessage.Direction.TOSERVER);
|
||||
}
|
||||
|
||||
@OnMessage
|
||||
public void onMessage(byte[] b, Session session) throws IOException {
|
||||
packetHandler.act(b);
|
||||
logger.debug("Received packet from browser");
|
||||
|
||||
// Enqueue all packets we receive to ensure we preserve correct packet order.
|
||||
packetQueue.enqueue(b);
|
||||
|
||||
// Flush everything if we are connected.
|
||||
// We also flush when connection state changes to connected.
|
||||
if (state.isConnected()) {
|
||||
packetQueue.flush();
|
||||
}
|
||||
}
|
||||
|
||||
@OnClose
|
||||
|
@ -94,7 +127,7 @@ public class NitroWebsocketClient implements NitroSession {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Session getSession() {
|
||||
public org.eclipse.jetty.websocket.api.Session getSession() {
|
||||
return activeSession;
|
||||
}
|
||||
|
||||
|
@ -132,7 +165,7 @@ public class NitroWebsocketClient implements NitroSession {
|
|||
|
||||
// Reset program state.
|
||||
proxySetter.setProxy(null);
|
||||
stateSetter.setState(HState.ABORTING);
|
||||
state.setAborting();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,20 +2,34 @@ package gearth.protocol.connection.proxy.nitro.websocket;
|
|||
|
||||
import gearth.protocol.HConnection;
|
||||
import gearth.protocol.HMessage;
|
||||
import gearth.protocol.connection.proxy.nitro.NitroConnectionState;
|
||||
import gearth.protocol.connection.proxy.nitro.NitroConstants;
|
||||
import gearth.protocol.packethandler.PacketHandler;
|
||||
import gearth.protocol.packethandler.nitro.NitroPacketHandler;
|
||||
import org.eclipse.jetty.websocket.api.extensions.ExtensionConfig;
|
||||
import org.eclipse.jetty.websocket.jsr356.JsrExtension;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.eclipse.jetty.http.HttpField;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
import org.eclipse.jetty.websocket.api.Session;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketListener;
|
||||
import org.eclipse.jetty.websocket.client.ClientUpgradeRequest;
|
||||
import org.eclipse.jetty.websocket.client.WebSocketClient;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.websocket.*;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.*;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class NitroWebsocketServer extends Endpoint implements NitroSession {
|
||||
public class NitroWebsocketServer implements WebSocketListener, NitroSession {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(NitroWebsocketServer.class);
|
||||
|
||||
|
@ -25,78 +39,56 @@ public class NitroWebsocketServer extends Endpoint implements NitroSession {
|
|||
"Sec-WebSocket-Version",
|
||||
"Host",
|
||||
"Connection",
|
||||
"Upgrade"
|
||||
"Upgrade",
|
||||
"User-Agent", // Added by default
|
||||
"Accept-Encoding", // Added by default
|
||||
"Cache-Control", // Added by default
|
||||
"Pragma" // Added by default
|
||||
));
|
||||
|
||||
private final PacketHandler packetHandler;
|
||||
private final NitroWebsocketClient client;
|
||||
private final NitroConnectionState state;
|
||||
private Session activeSession = null;
|
||||
|
||||
public NitroWebsocketServer(HConnection connection, NitroWebsocketClient client) {
|
||||
public NitroWebsocketServer(HConnection connection, NitroWebsocketClient client, NitroConnectionState state) {
|
||||
this.client = client;
|
||||
this.state = state;
|
||||
this.packetHandler = new NitroPacketHandler(HMessage.Direction.TOCLIENT, client, connection.getExtensionHandler(), connection.getTrafficObservables());
|
||||
}
|
||||
|
||||
public void connect(String websocketUrl, Map<String, List<String>> clientHeaders) throws IOException {
|
||||
try {
|
||||
logger.info("Connecting to origin websocket at {}", websocketUrl);
|
||||
logger.info("Building origin websocket connection ({})", websocketUrl);
|
||||
|
||||
ClientEndpointConfig.Builder builder = ClientEndpointConfig.Builder.create();
|
||||
final WebSocketClient client = createWebSocketClient();
|
||||
|
||||
builder.extensions(Collections.singletonList(new JsrExtension(new ExtensionConfig("permessage-deflate;client_max_window_bits"))));
|
||||
final ClientUpgradeRequest request = new ClientUpgradeRequest();
|
||||
|
||||
builder.configurator(new ClientEndpointConfig.Configurator() {
|
||||
@Override
|
||||
public void beforeRequest(Map<String, List<String>> headers) {
|
||||
clientHeaders.forEach((key, value) -> {
|
||||
if (SKIP_HEADERS.contains(key)) {
|
||||
return;
|
||||
}
|
||||
request.addExtensions("permessage-deflate");
|
||||
|
||||
headers.remove(key);
|
||||
headers.put(key, value);
|
||||
});
|
||||
clientHeaders.forEach((key, value) -> {
|
||||
if (SKIP_HEADERS.contains(key)) {
|
||||
return;
|
||||
}
|
||||
|
||||
request.setHeader(key, value);
|
||||
});
|
||||
|
||||
ClientEndpointConfig config = builder.build();
|
||||
if (clientHeaders.containsKey("User-Agent")) {
|
||||
final String realUserAgent = clientHeaders.get(HttpHeader.USER_AGENT.toString()).get(0);
|
||||
final HttpField clientUserAgent = new HttpField(HttpHeader.USER_AGENT, realUserAgent);
|
||||
|
||||
ContainerProvider.getWebSocketContainer().connectToServer(this, config, URI.create(websocketUrl));
|
||||
|
||||
logger.info("Connected to origin websocket");
|
||||
} catch (DeploymentException e) {
|
||||
throw new IOException("Failed to deploy websocket client", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpen(Session session, EndpointConfig config) {
|
||||
this.activeSession = session;
|
||||
this.activeSession.setMaxBinaryMessageBufferSize(NitroConstants.WEBSOCKET_BUFFER_SIZE);
|
||||
this.activeSession.addMessageHandler(new MessageHandler.Whole<byte[]>() {
|
||||
@Override
|
||||
public void onMessage(byte[] message) {
|
||||
try {
|
||||
packetHandler.act(message);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
client.getHttpClient().setUserAgentField(clientUserAgent);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose(Session session, CloseReason closeReason) {
|
||||
// Hotel closed connection.
|
||||
client.shutdownProxy();
|
||||
}
|
||||
logger.info("Connecting to origin websocket at {}", websocketUrl);
|
||||
|
||||
@Override
|
||||
public void onError(Session session, Throwable throwable) {
|
||||
throwable.printStackTrace();
|
||||
|
||||
// Shutdown.
|
||||
client.shutdownProxy();
|
||||
client.start();
|
||||
client.connect(this, URI.create(websocketUrl), request);
|
||||
} catch (Exception e) {
|
||||
throw new IOException("Failed to start websocket client to origin " + websocketUrl, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -118,10 +110,87 @@ public class NitroWebsocketServer extends Endpoint implements NitroSession {
|
|||
|
||||
try {
|
||||
activeSession.close();
|
||||
} catch (IOException e) {
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
activeSession = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWebSocketBinary(byte[] bytes, int i, int i1) {
|
||||
try {
|
||||
packetHandler.act(bytes);
|
||||
} catch (IOException e) {
|
||||
logger.error("Failed to handle packet", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWebSocketText(String s) {
|
||||
logger.warn("Received text message from hotel");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWebSocketClose(int i, String s) {
|
||||
// Hotel closed connection.
|
||||
client.shutdownProxy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWebSocketConnect(org.eclipse.jetty.websocket.api.Session session) {
|
||||
activeSession = session;
|
||||
state.setConnected(HMessage.Direction.TOCLIENT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWebSocketError(Throwable throwable) {
|
||||
throwable.printStackTrace();
|
||||
|
||||
// Shutdown.
|
||||
client.shutdownProxy();
|
||||
}
|
||||
|
||||
private SSLContext createSSLContext() {
|
||||
final TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {
|
||||
public X509Certificate[] getAcceptedIssuers() {
|
||||
return new X509Certificate[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkClientTrusted(X509Certificate[] certs, String authType) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkServerTrusted(X509Certificate[] certs, String authType) {
|
||||
}
|
||||
}};
|
||||
|
||||
try {
|
||||
final SSLContext sslContext = SSLContext.getInstance("TLS");
|
||||
|
||||
sslContext.init(null, trustAllCerts, new SecureRandom());
|
||||
|
||||
return sslContext;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Failed to setup ssl context", e);
|
||||
}
|
||||
}
|
||||
|
||||
private HttpClient createHttpClient() {
|
||||
final SslContextFactory.Client factory = new SslContextFactory.Client();
|
||||
|
||||
factory.setSslContext(createSSLContext());
|
||||
|
||||
return new HttpClient(factory);
|
||||
}
|
||||
|
||||
private WebSocketClient createWebSocketClient() {
|
||||
final WebSocketClient client = new WebSocketClient(createHttpClient());
|
||||
|
||||
client.getPolicy().setMaxBinaryMessageSize(NitroConstants.WEBSOCKET_BUFFER_SIZE);
|
||||
client.getPolicy().setMaxTextMessageSize(NitroConstants.WEBSOCKET_BUFFER_SIZE);
|
||||
|
||||
return client;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -134,6 +134,10 @@ public class MacOsHabboClient extends HabboClient {
|
|||
|
||||
private static byte[] hexStringToByteArray(String s) {
|
||||
int len = s.length();
|
||||
if (len % 2 == 1) {
|
||||
s = "0" + s;
|
||||
len += 1;
|
||||
}
|
||||
byte[] data = new byte[len / 2];
|
||||
for (int i = 0; i < len; i += 2) {
|
||||
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
|
||||
|
|
|
@ -6,13 +6,17 @@ import gearth.protocol.connection.proxy.nitro.websocket.NitroSession;
|
|||
import gearth.protocol.packethandler.PacketHandler;
|
||||
import gearth.protocol.packethandler.PayloadBuffer;
|
||||
import gearth.services.extension_handler.ExtensionHandler;
|
||||
import org.eclipse.jetty.websocket.api.Session;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.websocket.Session;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public class NitroPacketHandler extends PacketHandler {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(NitroPacketHandler.class);
|
||||
|
||||
private final HMessage.Direction direction;
|
||||
private final NitroSession session;
|
||||
private final PayloadBuffer payloadBuffer;
|
||||
|
@ -31,6 +35,7 @@ public class NitroPacketHandler extends PacketHandler {
|
|||
final Session localSession = session.getSession();
|
||||
|
||||
if (localSession == null) {
|
||||
logger.warn("Discarding {} bytes because the session for direction {} was null", buffer.length, this.direction);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -39,7 +44,13 @@ public class NitroPacketHandler extends PacketHandler {
|
|||
buffer = buffer.clone();
|
||||
}
|
||||
|
||||
localSession.getAsyncRemote().sendBinary(ByteBuffer.wrap(buffer));
|
||||
try {
|
||||
localSession.getRemote().sendBytes(ByteBuffer.wrap(buffer));
|
||||
} catch (IOException e) {
|
||||
logger.error("Error sending packet to nitro client", e);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -357,7 +357,7 @@ public class UiLoggerController implements Initializable {
|
|||
public void updateLoggerInfo() {
|
||||
Platform.runLater(() -> {
|
||||
viewIncoming.setKey(1, "ext.logger.state." + (chkViewIncoming.isSelected() ? "true" : "false"));
|
||||
viewIncoming.setKey(1, "ext.logger.state." + (chkViewOutgoing.isSelected() ? "true" : "false"));
|
||||
viewOutgoing.setKey(1, "ext.logger.state." + (chkViewOutgoing.isSelected() ? "true" : "false"));
|
||||
autoScroll.setKey(1, "ext.logger.state." + (chkAutoscroll.isSelected() ? "true" : "false"));
|
||||
filtered.setFormat("%s: " + filteredAmount);
|
||||
|
||||
|
|
105
G-Earth/src/main/java/gearth/ui/GEarthTrayIcon.java
Normal file
105
G-Earth/src/main/java/gearth/ui/GEarthTrayIcon.java
Normal file
|
@ -0,0 +1,105 @@
|
|||
package gearth.ui;
|
||||
|
||||
import gearth.GEarth;
|
||||
import gearth.services.extension_handler.extensions.GEarthExtension;
|
||||
import gearth.services.extension_handler.extensions.extensionproducers.ExtensionProducerFactory;
|
||||
import gearth.services.extension_handler.extensions.implementations.network.NetworkExtensionServer;
|
||||
import javafx.application.Platform;
|
||||
import javafx.embed.swing.SwingFXUtils;
|
||||
import javafx.scene.image.Image;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* Adds a {@link TrayIcon} to the {@link SystemTray} for this G-Earth instance.
|
||||
*
|
||||
* @author Dorving
|
||||
*/
|
||||
public final class GEarthTrayIcon {
|
||||
|
||||
private static final String TO_FRONT_LABEL = "To front";
|
||||
private static final String TO_BACK_LABEL = "To back";
|
||||
|
||||
private static PopupMenu menu;
|
||||
|
||||
public static void updateOrCreate(Image image) {
|
||||
|
||||
if (!SystemTray.isSupported())
|
||||
return;
|
||||
|
||||
final NetworkExtensionServer server = ExtensionProducerFactory.getExtensionServer();
|
||||
final BufferedImage awtImage = SwingFXUtils.fromFXImage(image, null);
|
||||
final String appTitle = "G-Earth " + GEarth.version + " (" + server.getPort() + ")";
|
||||
|
||||
final Optional<TrayIcon> trayIcon = Stream.of(SystemTray.getSystemTray().getTrayIcons())
|
||||
.filter(other -> Objects.equals(other.getToolTip(), appTitle))
|
||||
.findFirst();
|
||||
if (trayIcon.isPresent()) {
|
||||
EventQueue.invokeLater(() -> trayIcon.get().setImage(awtImage));
|
||||
} else {
|
||||
menu = new PopupMenu();
|
||||
menu.add(createToFrontOrBackMenuItem());
|
||||
menu.addSeparator();
|
||||
menu.addSeparator();
|
||||
menu.add(createInstallMenuItem());
|
||||
try {
|
||||
SystemTray.getSystemTray().add(new TrayIcon(awtImage, appTitle, menu));
|
||||
} catch (AWTException e) {
|
||||
e.printStackTrace();
|
||||
menu = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static MenuItem createToFrontOrBackMenuItem() {
|
||||
final MenuItem showMenuItem = new MenuItem(TO_FRONT_LABEL);
|
||||
showMenuItem.addActionListener(e -> {
|
||||
if (Objects.equals(showMenuItem.getLabel(), TO_FRONT_LABEL)) {
|
||||
showMenuItem.setLabel(TO_BACK_LABEL);
|
||||
Platform.runLater(() -> GEarth.main.getController().getStage().toFront());
|
||||
} else {
|
||||
showMenuItem.setLabel(TO_FRONT_LABEL);
|
||||
Platform.runLater(() -> GEarth.main.getController().getStage().toBack());
|
||||
}
|
||||
});
|
||||
return showMenuItem;
|
||||
}
|
||||
|
||||
private static MenuItem createInstallMenuItem() {
|
||||
final MenuItem showMenuItem = new MenuItem("Install Extension...");
|
||||
showMenuItem.addActionListener(e ->
|
||||
Optional.ofNullable(GEarth.main.getController())
|
||||
.map(c -> c.extensionsController)
|
||||
.ifPresent(c -> Platform.runLater(() -> {
|
||||
final Stage stage = c.parentController.getStage();
|
||||
final boolean isOnTop = stage.isAlwaysOnTop();
|
||||
stage.setAlwaysOnTop(true); // bit of a hack to force stage to front
|
||||
c.installBtnClicked(null);
|
||||
stage.setAlwaysOnTop(isOnTop);
|
||||
})));
|
||||
return showMenuItem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the argued extension as a menu item to {@link #menu}.
|
||||
*
|
||||
* @param extension the {@link GEarthExtension} to add to the {@link #menu}.
|
||||
*/
|
||||
public static void addExtension(GEarthExtension extension) {
|
||||
|
||||
if (menu == null)
|
||||
return;
|
||||
|
||||
final MenuItem menuItem = new MenuItem("Show "+extension.getTitle());
|
||||
EventQueue.invokeLater(() -> menu.insert(menuItem, 2));
|
||||
menuItem
|
||||
.addActionListener(e -> Platform.runLater(() -> extension.getClickedObservable().fireEvent()));
|
||||
extension.getDeletedObservable()
|
||||
.addListener(() -> EventQueue.invokeLater(() -> menu.remove(menuItem)));
|
||||
}
|
||||
}
|
|
@ -8,6 +8,7 @@ import gearth.services.extension_handler.extensions.implementations.network.exec
|
|||
import gearth.services.extension_handler.extensions.implementations.network.executer.ExtensionRunner;
|
||||
import gearth.services.extension_handler.extensions.implementations.network.executer.ExtensionRunnerFactory;
|
||||
import gearth.services.g_python.GPythonShell;
|
||||
import gearth.ui.GEarthTrayIcon;
|
||||
import gearth.ui.SubForm;
|
||||
import gearth.ui.subforms.extensions.logger.ExtensionLogger;
|
||||
import gearth.ui.translations.LanguageBundle;
|
||||
|
@ -18,6 +19,7 @@ import javafx.scene.control.*;
|
|||
import javafx.scene.layout.GridPane;
|
||||
import javafx.scene.layout.VBox;
|
||||
import javafx.stage.FileChooser;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
|
@ -54,9 +56,10 @@ public class ExtensionsController extends SubForm {
|
|||
protected void onParentSet() {
|
||||
ExtensionItemContainerProducer producer = new ExtensionItemContainerProducer(extensioncontainer, scroller);
|
||||
extensionHandler = new ExtensionHandler(getHConnection());
|
||||
extensionHandler.getObservable().addListener((e -> {
|
||||
Platform.runLater(() -> producer.extensionConnected(e));
|
||||
}));
|
||||
extensionHandler.getObservable().addListener((e -> Platform.runLater(() -> {
|
||||
producer.extensionConnected(e);
|
||||
GEarthTrayIcon.addExtension(e);
|
||||
})));
|
||||
|
||||
//noinspection OptionalGetWithoutIsPresent
|
||||
networkExtensionsProducer
|
||||
|
|
|
@ -147,7 +147,7 @@ alert.outdated.content.newversion=Uma nova versão do G-Earth foi encontrada
|
|||
alert.outdated.content.update=Atualizar para a versão mais recente
|
||||
|
||||
### Alert - Invalid connection
|
||||
alert.invalidconnection.content=Você entrou com inforções de conexão inválidas, o G-Earth não conseguiu se conectar
|
||||
alert.invalidconnection.content=Você entrou com informações de conexão inválidas, o G-Earth não conseguiu se conectar
|
||||
|
||||
### Alert - Nitro root certificate
|
||||
alert.rootcertificate.title=Instalação de certificado do root
|
||||
|
@ -169,7 +169,7 @@ alert.somethingwentwrong.content=Algo inesperado aconteceu!\n\
|
|||
Vá para nossa página de Solução de problemas para resolver o ocorrido:
|
||||
|
||||
### Alert - Allow extension connection
|
||||
alert.extconnection.content=Exntesão "%s" tentou se conectar mas é desconcida pelo G-Earth,\n\
|
||||
alert.extconnection.content=Extensão "%s" tentou se conectar mas é desconhecida pelo G-Earth,\n\
|
||||
aceitar essa conexão?
|
||||
|
||||
### Alert - G-Python error
|
||||
|
@ -183,8 +183,8 @@ alert.gpythonerror.content=Algo inesperado aconteceu executando o terminal G-Pyt
|
|||
## Internal extension
|
||||
|
||||
### Internal extension - G-ExtensionStore
|
||||
ext.store.elapsedtime.second.single=secondo
|
||||
ext.store.elapsedtime.second.multiple=secondos
|
||||
ext.store.elapsedtime.second.single=segundo
|
||||
ext.store.elapsedtime.second.multiple=segundos
|
||||
ext.store.elapsedtime.minute.single=minuto
|
||||
ext.store.elapsedtime.minute.multiple=minutos
|
||||
ext.store.elapsedtime.hour.single=hora
|
||||
|
@ -219,7 +219,7 @@ ext.store.extension.details.screenshot=Captura de tela
|
|||
ext.store.extension.author.reputation=reputação
|
||||
ext.store.extension.author.releases=lançamentos
|
||||
|
||||
ext.store.extension.warning.requirement=Aviso: o framework requer --url:instalações adicionais-
|
||||
ext.store.extension.warning.requirement=Aviso: o framework requer --url:additional installations-
|
||||
! IMPORTANT: the previous line has to end with the --url component like the english version
|
||||
ext.store.extension.warning.unstable=Aviso: esta extensão foi marcada como instável!
|
||||
|
||||
|
@ -272,17 +272,17 @@ ext.store.categories.title=Categorias
|
|||
ext.store.categories.description=Explore os diferentes tipos de extensões que o G-Earth tem a oferecer
|
||||
ext.store.categories.contenttitle=Categorias
|
||||
|
||||
ext.store.fail.unzip=Error while unzipping
|
||||
ext.store.fail.invalidurl=Invalid extension URL
|
||||
ext.store.fail.notavailable=Extension not available in repository
|
||||
ext.store.fail.alreadyexists=Something went wrong creating the extension directory, does the extension already exist?
|
||||
ext.store.fail.notfound=Extension wasn't found
|
||||
ext.store.fail.uninstall=Something went wrong with uninstalling the extension, make sure to disconnect the extension if it was still running.
|
||||
ext.store.fail.unzip=Erro ao descompactar
|
||||
ext.store.fail.invalidurl=URL de extensão inválida
|
||||
ext.store.fail.notavailable=Extensão não disponível no repositório
|
||||
ext.store.fail.alreadyexists=Algo deu errado ao criar o diretório de extensão, a extensão já existe?
|
||||
ext.store.fail.notfound=Extensão não foi encontrada
|
||||
ext.store.fail.uninstall=Algo deu errado ao desinstalar a extensão, certifique-se de desconectar a extensão se ela ainda estiver em execução.
|
||||
|
||||
ext.store.ordering.rating=Rating
|
||||
ext.store.ordering.alphabetical=Alphabetical
|
||||
ext.store.ordering.lastupdated=Last updated
|
||||
ext.store.ordering.newreleases=New releases
|
||||
ext.store.ordering.rating=Avaliação
|
||||
ext.store.ordering.alphabetical=Alfabético
|
||||
ext.store.ordering.lastupdated=Última atualização
|
||||
ext.store.ordering.newreleases=Novos lançamentos
|
||||
|
||||
### Internal extension - Logger
|
||||
ext.logger.menu.window=Janela
|
||||
|
@ -307,7 +307,7 @@ ext.logger.menu.packets.displaydetails.byterep.legacy=Legado
|
|||
ext.logger.menu.packets.displaydetails.byterep.hexdump=Hexdump
|
||||
ext.logger.menu.packets.displaydetails.byterep.rawhex=Hex cru
|
||||
ext.logger.menu.packets.displaydetails.byterep.none=Nenhum
|
||||
ext.logger.menu.packets.displaydetails.message=Menssagem
|
||||
ext.logger.menu.packets.displaydetails.message=Mensagem
|
||||
ext.logger.menu.packets.displaydetails.message.name=Nome
|
||||
ext.logger.menu.packets.displaydetails.message.hash=Hash
|
||||
ext.logger.menu.packets.displaydetails.message.id=Id
|
||||
|
|
|
@ -36,7 +36,6 @@ Name | Language | Developers | Github
|
|||
--- | --- | --- | --- |
|
||||
G-Earth (Native) | Java | sirjonasxx | https://github.com/sirjonasxx/G-Earth
|
||||
G-Python<sup>1</sup> | Python | sirjonasxx | https://github.com/sirjonasxx/G-Python
|
||||
Geode | C# & Visual Basic | ArachisH, LilithRainbows | https://github.com/LilithRainbows/Geode
|
||||
Xabbo | C# | b7 | https://github.com/b7c/Xabbo.GEarth
|
||||
Xabbo scripter<sup>2</sup> | C# | b7 | https://github.com/b7c/Xabbo.Scripter
|
||||
G-Node | Node.js | WiredSpast | https://github.com/WiredSpast/G-Node
|
||||
|
|
|
@ -1,24 +1,89 @@
|
|||
**NOTE: Currently supported browsers: ONLY Firefox and Chromium, works on Habbo AIR too**
|
||||
|
||||
In order to run G-Earth on macOs, you'll need to sign G-Mem (our memory searcher). This wiki page will cover that process.
|
||||
# MacOS Installation Guide
|
||||
|
||||
First we'll create a certificate in order to sign it:
|
||||
1. Open the Keychain Access application (You may find it inside Utilities).£
|
||||
2. Select Certificate Assistant -> Create a Certificate.<br>
|
||||
![](https://i.imgur.com/G6SS6ac.png)
|
||||
3. Choose a name for the certificate (I'll use "gmem-cert") and set "Certificate Type" to "Code Signing". Also select "Let me override defaults" option.<br>
|
||||
![](https://i.imgur.com/CAUI5Xi.png)
|
||||
4. Click on "Continue" until "Specify a Location For The Certificate" appears, then set "Keychain" to "System".<br>
|
||||
![](https://i.imgur.com/HwLDtmE.png)
|
||||
5. Continue, the certificate will be created then.<br>
|
||||
![](https://i.imgur.com/gYiKmZA.png)
|
||||
G-Earth depends on an application named [G-Mem](https://github.com/sirjonasxx/G-Mem),
|
||||
this application scans the memory contents of the Habbo client applicaton and extracts a cipher key
|
||||
that is used to decrypt packets coming from the Habbo server.
|
||||
|
||||
Once created, we are able to codesign gmem from Terminal<br>
|
||||
`codesign -fs "gmem-cert" <G-Earth_Path>/G-Mem`
|
||||
There is a few steps u have to complete in order to get it to work on MacOS.
|
||||
|
||||
![](https://i.imgur.com/xkryoJz.png)
|
||||
## Code-Sign G-Mem file and make it executable
|
||||
|
||||
Now you're ready to open G-Earth from Terminal<br>
|
||||
`sudo java -jar G-Earth.jar`
|
||||
### Certificate Creation
|
||||
1. Open `Keychain Access` (press `⌘ + Enter`, type `KeyChain Access` to open it from spotlight)
|
||||
2. Navigate from the top menu to `Keychain Access > Certificate Assistant > Create Certificate...`
|
||||
![Screenshot 2023-03-30 at 14 36 47](https://user-images.githubusercontent.com/102377087/228837955-81182786-ac47-46e5-a5e2-1ca2e257751f.png)
|
||||
3. In the `Create Your Certificate` do the following:
|
||||
* Set `Name:` to `gmem-cert`
|
||||
* Set `Cerificate Type:` to `Code Signing`
|
||||
* Toggle the `Let me override default` button
|
||||
|
||||
![Screenshot 2023-03-30 at 14 40 28](https://user-images.githubusercontent.com/102377087/228838867-57e465bc-5b83-4b1a-a8cc-3dd6d1e95353.png)
|
||||
|
||||
5. Press `Continue` until you reach the `Specify a Location For The Certificate`, now do the following:
|
||||
* Set `Keychain:` to `System`
|
||||
|
||||
![Screenshot 2023-03-30 at 14 42 50](https://user-images.githubusercontent.com/102377087/228839468-982365d9-925c-44cf-a87d-fc6c268d05c8.png)
|
||||
|
||||
6. Enter your login credentials when prompted and press `Done`
|
||||
|
||||
### Signing of G-Mem
|
||||
1. Open `Terminal` (press `⌘ + Enter`, type `Terminal` to open it from spotlight)
|
||||
2. Type `codesign -fs "gmem-cert" ` (do not press enter yet)
|
||||
3. Drag the `G-Mem` file into your terminal window *(this will append the path to the terminal)*
|
||||
|
||||
Your terminal window should now resemble the following:
|
||||
|
||||
![Screenshot 2023-03-30 at 14 49 28](https://user-images.githubusercontent.com/102377087/228841126-77b0184b-4c7d-44e0-9f7c-56103a957a81.png)
|
||||
|
||||
4. Now press enter and enter your login credentials when prompted.
|
||||
|
||||
### Making G-Mem executable
|
||||
1. Open `Terminal` (press `⌘ + Enter`, type `Terminal` to open it from spotlight)
|
||||
2. Type `chmod 755 ` (do not press enter yet)
|
||||
3. Drag the `G-Mem` file into your terminal window *(this will append the path to the terminal)*
|
||||
|
||||
Your terminal window should now resemble the following:
|
||||
|
||||
![Screenshot 2023-03-30 at 14 52 29](https://user-images.githubusercontent.com/102377087/228841918-3205014b-5de8-431d-ae4d-d10b8ceeed03.png)
|
||||
|
||||
4. Now press enter and verify the `Kind` of the `G-Mem` file is now `Unix Executable File`
|
||||
|
||||
![Screenshot 2023-03-30 at 14 54 15](https://user-images.githubusercontent.com/102377087/228842389-78ea857e-3414-43d0-8270-91f8185ab57f.png)
|
||||
|
||||
## Disabling SIP
|
||||
|
||||
Modern machines running MacOS have a security feature that shields of the memory of processes from other processes.
|
||||
Depending on your machine you may have to disable SIP.
|
||||
|
||||
**For M1 macs it is required to disable SIP.**
|
||||
|
||||
### :warning: CAUTION :warning:
|
||||
Turning off SIP allows any program with sudo privileges to modify memory contents of other processes. If you use pirated software, or other unverified apps, DO NOT DO THIS for your own safety! See the following stackoverflow post for some more info: https://apple.stackexchange.com/a/412281.
|
||||
|
||||
A guide for disabling SIP can be found here: https://developer.apple.com/documentation/security/disabling_and_enabling_system_integrity_protection
|
||||
|
||||
## Launching G-Earth
|
||||
1. Open `Terminal` (press `⌘ + Enter`, type `Terminal` to open it from spotlight)
|
||||
2. Type `sudo java -jar `
|
||||
3. Drag the `G-Earth.jar` file into your terminal window *(this will append the path to the terminal)*
|
||||
|
||||
Your terminal window should now resemble the following:
|
||||
|
||||
![Screenshot 2023-03-30 at 15 00 59](https://user-images.githubusercontent.com/102377087/228843994-f7713373-9f19-49b0-b7e7-0645a16c4fce.png)
|
||||
|
||||
5. Press enter and fill in your password if prompted
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### 🚫 Apple can’t check app for malicious software
|
||||
In this case, you can grant an exception for a blocked app by clicking the `Open Anyway` button in Privacy & Security settings.
|
||||
This button is available for about an hour after you try to open the app. Where it appears exactly depends on the OS version u are running,
|
||||
more details about it can be found here: https://support.apple.com/en-gb/guide/mac-help/mchleab3a043/mac
|
||||
|
||||
### Other
|
||||
If you experience any other issues and the [Troubleshooting Page](https://github.com/sirjonasxx/G-Earth/wiki/Troubleshooting) doesn't help,
|
||||
|
||||
it might be useful to have a look at the following issues: [#67](../issues/67) [#10](../issues/10)
|
||||
|
||||
If you experience any other issues and the troubleshooting page doesn't help, it might be useful to have a look at the following issues: [#67](../issues/67) [#10](../issues/10)
|
Loading…
Reference in New Issue
Block a user