mirror of
https://github.com/Retera/WarsmashModEngine.git
synced 2022-07-31 17:38:59 +02:00
Some bug fixes and network changes
This commit is contained in:
parent
7e5c8850e8
commit
dd5544109f
@ -3,8 +3,7 @@ package com.etheller.warsmash.networking;
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.etheller.warsmash.networking.udp.OrderedUdpClient;
|
||||
@ -17,7 +16,9 @@ public class WarsmashClient implements ServerToClientListener, GameTurnManager {
|
||||
private final War3MapViewer game;
|
||||
private final Map<Integer, CPlayerUnitOrderExecutor> indexToExecutor = new HashMap<>();
|
||||
private int latestCompletedTurn = -1;
|
||||
private int latestLocallyRequestedTurn = -1;
|
||||
private final WarsmashClientWriter writer;
|
||||
private final Queue<QueuedMessage> queuedMessages = new ArrayDeque<>();
|
||||
|
||||
public WarsmashClient(final InetAddress serverAddress, final War3MapViewer game)
|
||||
throws UnknownHostException, IOException {
|
||||
@ -52,7 +53,19 @@ public class WarsmashClient implements ServerToClientListener, GameTurnManager {
|
||||
Gdx.app.postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
executor.issueTargetOrder(unitHandleId, abilityHandleId, orderId, targetHandleId, queue);
|
||||
int currentServerTurnInProgress = latestCompletedTurn + 1;
|
||||
if(currentServerTurnInProgress > latestLocallyRequestedTurn) {
|
||||
queuedMessages.add(new QueuedMessage(latestCompletedTurn) {
|
||||
@Override
|
||||
public void run() {
|
||||
executor.issueTargetOrder(unitHandleId, abilityHandleId, orderId, targetHandleId, queue);
|
||||
}
|
||||
});
|
||||
} else if(currentServerTurnInProgress == latestLocallyRequestedTurn) {
|
||||
executor.issueTargetOrder(unitHandleId, abilityHandleId, orderId, targetHandleId, queue);
|
||||
} else {
|
||||
System.err.println("Turn tick system mismatch: " + currentServerTurnInProgress + " < " + latestLocallyRequestedTurn);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -64,7 +77,19 @@ public class WarsmashClient implements ServerToClientListener, GameTurnManager {
|
||||
Gdx.app.postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
executor.issuePointOrder(unitHandleId, abilityHandleId, orderId, x, y, queue);
|
||||
int currentServerTurnInProgress = latestCompletedTurn + 1;
|
||||
if(currentServerTurnInProgress > latestLocallyRequestedTurn) {
|
||||
queuedMessages.add(new QueuedMessage(latestCompletedTurn) {
|
||||
@Override
|
||||
public void run() {
|
||||
executor.issuePointOrder(unitHandleId, abilityHandleId, orderId, x, y, queue);
|
||||
}
|
||||
});
|
||||
} else if(currentServerTurnInProgress == latestLocallyRequestedTurn) {
|
||||
executor.issuePointOrder(unitHandleId, abilityHandleId, orderId, x, y, queue);;
|
||||
} else {
|
||||
System.err.println("Turn tick system mismatch: " + currentServerTurnInProgress + " < " + latestLocallyRequestedTurn);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -77,7 +102,19 @@ public class WarsmashClient implements ServerToClientListener, GameTurnManager {
|
||||
Gdx.app.postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
executor.issueDropItemAtPointOrder(unitHandleId, abilityHandleId, orderId, targetHandleId, x, y, queue);
|
||||
int currentServerTurnInProgress = latestCompletedTurn + 1;
|
||||
if(currentServerTurnInProgress > latestLocallyRequestedTurn) {
|
||||
queuedMessages.add(new QueuedMessage(latestCompletedTurn) {
|
||||
@Override
|
||||
public void run() {
|
||||
executor.issueDropItemAtPointOrder(unitHandleId, abilityHandleId, orderId, targetHandleId, x, y, queue);
|
||||
}
|
||||
});
|
||||
} else if(currentServerTurnInProgress == latestLocallyRequestedTurn) {
|
||||
executor.issueDropItemAtPointOrder(unitHandleId, abilityHandleId, orderId, targetHandleId, x, y, queue);
|
||||
} else {
|
||||
System.err.println("Turn tick system mismatch: " + currentServerTurnInProgress + " < " + latestLocallyRequestedTurn);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -89,7 +126,19 @@ public class WarsmashClient implements ServerToClientListener, GameTurnManager {
|
||||
Gdx.app.postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
executor.issueImmediateOrder(unitHandleId, abilityHandleId, orderId, queue);
|
||||
int currentServerTurnInProgress = latestCompletedTurn + 1;
|
||||
if(currentServerTurnInProgress > latestLocallyRequestedTurn) {
|
||||
queuedMessages.add(new QueuedMessage(latestCompletedTurn) {
|
||||
@Override
|
||||
public void run() {
|
||||
executor.issueImmediateOrder(unitHandleId, abilityHandleId, orderId, queue);
|
||||
}
|
||||
});
|
||||
} else if(currentServerTurnInProgress == latestLocallyRequestedTurn) {
|
||||
executor.issueImmediateOrder(unitHandleId, abilityHandleId, orderId, queue);
|
||||
} else {
|
||||
System.err.println("Turn tick system mismatch: " + currentServerTurnInProgress + " < " + latestLocallyRequestedTurn);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -100,13 +149,28 @@ public class WarsmashClient implements ServerToClientListener, GameTurnManager {
|
||||
Gdx.app.postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
executor.unitCancelTrainingItem(unitHandleId, cancelIndex);
|
||||
int currentServerTurnInProgress = latestCompletedTurn + 1;
|
||||
if(currentServerTurnInProgress > latestLocallyRequestedTurn) {
|
||||
queuedMessages.add(new QueuedMessage(latestCompletedTurn) {
|
||||
@Override
|
||||
public void run() {
|
||||
executor.unitCancelTrainingItem(unitHandleId, cancelIndex);
|
||||
}
|
||||
});
|
||||
} else if(currentServerTurnInProgress == latestLocallyRequestedTurn) {
|
||||
executor.unitCancelTrainingItem(unitHandleId, cancelIndex);
|
||||
} else {
|
||||
System.err.println("Turn tick system mismatch: " + currentServerTurnInProgress + " < " + latestLocallyRequestedTurn);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finishedTurn(final int gameTurnTick) {
|
||||
if(WarsmashConstants.VERBOSE_LOGGING) {
|
||||
System.out.println("finishedTurn " + gameTurnTick);
|
||||
}
|
||||
Gdx.app.postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
@ -119,6 +183,10 @@ public class WarsmashClient implements ServerToClientListener, GameTurnManager {
|
||||
public void turnCompleted(final int gameTurnTick) {
|
||||
this.writer.finishedTurn(gameTurnTick);
|
||||
this.writer.send();
|
||||
latestLocallyRequestedTurn = gameTurnTick;
|
||||
while(!queuedMessages.isEmpty() && queuedMessages.peek().messageTurnTick == latestLocallyRequestedTurn) {
|
||||
queuedMessages.poll().run();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -142,6 +210,7 @@ public class WarsmashClient implements ServerToClientListener, GameTurnManager {
|
||||
// Not doing anything here at the moment. The act of the server sending us that packet
|
||||
// will let the middle layer UDP system know to re-request any lost packets based
|
||||
// on the heartbeat seq no. But at app layer, here, we can ignore it.
|
||||
System.out.println("got heartbeat() from server");
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -152,4 +221,18 @@ public class WarsmashClient implements ServerToClientListener, GameTurnManager {
|
||||
public WarsmashClientWriter getWriter() {
|
||||
return this.writer;
|
||||
}
|
||||
|
||||
private static abstract class QueuedMessage implements Runnable {
|
||||
private int messageTurnTick;
|
||||
|
||||
public QueuedMessage(int messageTurnTick) {
|
||||
this.messageTurnTick = messageTurnTick;
|
||||
}
|
||||
|
||||
public final int getMessageTurnTick() {
|
||||
return messageTurnTick;
|
||||
}
|
||||
|
||||
public abstract void run();
|
||||
}
|
||||
}
|
||||
|
@ -14,12 +14,13 @@ import com.etheller.warsmash.networking.udp.OrderedUdpServer;
|
||||
import com.etheller.warsmash.util.WarsmashConstants;
|
||||
|
||||
public class WarsmashServer implements ClientToServerListener {
|
||||
private static final int MAGIC_DELAY_OFFSET = 4;
|
||||
private final OrderedUdpServer udpServer;
|
||||
private final Map<SocketAddress, Integer> socketAddressToPlayerIndex = new HashMap<>();
|
||||
private final Set<SocketAddress> clientsAwaitingTurnFinished = new HashSet<>();
|
||||
private final Map<SocketAddress, Integer> clientToTurnFinished = new HashMap<>();
|
||||
private final List<Runnable> turnActions = new ArrayList<>();
|
||||
private final WarsmashServerWriter writer;
|
||||
private int currentTurnTick = 0;
|
||||
private int currentTurnTick = MAGIC_DELAY_OFFSET;
|
||||
private boolean gameStarted = false;
|
||||
private long lastServerHeartbeatTime = 0;
|
||||
|
||||
@ -40,7 +41,7 @@ public class WarsmashServer implements ClientToServerListener {
|
||||
}
|
||||
|
||||
private void startTurn() {
|
||||
this.clientsAwaitingTurnFinished.addAll(this.socketAddressToPlayerIndex.keySet());
|
||||
System.out.println("sending finishedTurn " + this.currentTurnTick);
|
||||
WarsmashServer.this.writer.finishedTurn(this.currentTurnTick);
|
||||
WarsmashServer.this.writer.send();
|
||||
this.currentTurnTick++;
|
||||
@ -139,25 +140,29 @@ public class WarsmashServer implements ClientToServerListener {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finishedTurn(final SocketAddress sourceAddress, final int gameTurnTick) {
|
||||
// System.out.println("finishedTurn(" + gameTurnTick + ") from " + sourceAddress);
|
||||
public void finishedTurn(final SocketAddress sourceAddress, final int clientGameTurnTick) {
|
||||
int gameTurnTick = clientGameTurnTick + MAGIC_DELAY_OFFSET;
|
||||
if(WarsmashConstants.VERBOSE_LOGGING) {
|
||||
System.out.println("finishedTurn(" + gameTurnTick + ") from " + sourceAddress);
|
||||
}
|
||||
if (!this.gameStarted) {
|
||||
throw new IllegalStateException(
|
||||
"Client should not send us finishedTurn() message when game has not started!");
|
||||
}
|
||||
if (gameTurnTick == this.currentTurnTick) {
|
||||
this.clientsAwaitingTurnFinished.remove(sourceAddress);
|
||||
if (this.clientsAwaitingTurnFinished.isEmpty()) {
|
||||
for (final Runnable turnAction : this.turnActions) {
|
||||
turnAction.run();
|
||||
}
|
||||
this.turnActions.clear();
|
||||
startTurn();
|
||||
clientToTurnFinished.put(sourceAddress, clientGameTurnTick);
|
||||
boolean allDone = true;
|
||||
for(SocketAddress clientAddress: socketAddressToPlayerIndex.keySet()) {
|
||||
Integer turnFinishedValue = clientToTurnFinished.get(clientAddress);
|
||||
if(turnFinishedValue == null || turnFinishedValue < clientGameTurnTick) {
|
||||
allDone = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
System.err.println("received bad finishedTurn() with remote gameTurnTick=" + gameTurnTick
|
||||
+ ", server local currenTurnTick=" + this.currentTurnTick);
|
||||
if (allDone) {
|
||||
for (final Runnable turnAction : this.turnActions) {
|
||||
turnAction.run();
|
||||
}
|
||||
this.turnActions.clear();
|
||||
startTurn();
|
||||
}
|
||||
}
|
||||
|
||||
@ -167,7 +172,7 @@ public class WarsmashServer implements ClientToServerListener {
|
||||
long currentTimeMillis = System.currentTimeMillis();
|
||||
if(currentTimeMillis - lastServerHeartbeatTime > 3000) {
|
||||
// 3 seconds of frame skipping, make sure we keep in contact with client
|
||||
|
||||
System.out.println("sending server heartbeat()");
|
||||
WarsmashServer.this.writer.heartbeat();
|
||||
WarsmashServer.this.writer.send();
|
||||
lastServerHeartbeatTime = currentTimeMillis;
|
||||
|
@ -8,7 +8,7 @@ public class WarsmashConstants {
|
||||
*/
|
||||
public static int GAME_VERSION = 1;
|
||||
public static final int REPLACEABLE_TEXTURE_LIMIT = 64;
|
||||
public static final float SIMULATION_STEP_TIME = 1 / 20f;
|
||||
public static final float SIMULATION_STEP_TIME = 1 /20f;
|
||||
public static final int PORT_NUMBER = 6115;
|
||||
public static final float BUILDING_CONSTRUCT_START_LIFE = 0.1f;
|
||||
public static final int BUILD_QUEUE_SIZE = 7;
|
||||
@ -26,4 +26,5 @@ public class WarsmashConstants {
|
||||
public static final String DEFAULT_STRING = "Default string";
|
||||
|
||||
public static final boolean CATCH_CURSOR = true;
|
||||
public static final boolean VERBOSE_LOGGING = true;
|
||||
}
|
||||
|
@ -299,6 +299,7 @@ public abstract class Node extends GenericNode {
|
||||
this.wasDirty = false;
|
||||
}
|
||||
|
||||
|
||||
this.updateObject(dt, scene);
|
||||
this.updateChildren(dt, scene);
|
||||
}
|
||||
|
@ -114,7 +114,10 @@ public abstract class SkeletalNode extends GenericNode {
|
||||
computedRotation = rotationHeap;
|
||||
|
||||
computedRotation.set(this.parent.inverseWorldRotation);
|
||||
computedRotation.mul(scene.camera.inverseRotation);
|
||||
if(scene!=null) {
|
||||
// TODO null scene is stupid, and happens rarely
|
||||
computedRotation.mul(scene.camera.inverseRotation);
|
||||
}
|
||||
|
||||
this.convertBasis(computedRotation);
|
||||
}
|
||||
|
@ -293,12 +293,6 @@ public class MdxComplexInstance extends ModelInstance {
|
||||
final MdxModel model = (MdxModel) this.model;
|
||||
final List<GenericObject> sortedGenericObjects = model.sortedGenericObjects;
|
||||
final Scene scene = this.scene;
|
||||
if(scene == null) {
|
||||
// too bad for this instance, this is not safe to update on null scene, got NPE from this during testing,
|
||||
// so we are going to skip this cycle entirely!
|
||||
// (Retera)
|
||||
return;
|
||||
}
|
||||
|
||||
// Update the nodes
|
||||
for (int i = 0, l = sortedNodes.length; i < l; i++) {
|
||||
@ -915,4 +909,15 @@ public class MdxComplexInstance extends ModelInstance {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int clampFrame(int frameToClamp) {
|
||||
final MdxModel model = (MdxModel) this.model;
|
||||
final int sequenceId = this.sequence;
|
||||
if(sequenceId >= 0 && sequenceId < model.sequences.size()) {
|
||||
final Sequence sequence = model.sequences.get(sequenceId);
|
||||
final long[] interval = sequence.getInterval();
|
||||
return (int)Math.max(interval[0], Math.min(interval[1], frameToClamp));
|
||||
}
|
||||
return frameToClamp;
|
||||
}
|
||||
}
|
||||
|
@ -105,7 +105,7 @@ public interface RenderWidget {
|
||||
if (SequenceUtils.randomSequence(this.instance, animationName, this.recycleSet,
|
||||
allowRarityVariations) != null) {
|
||||
if(lastWalkFrame != -1 && animationName == PrimaryTag.WALK && currentAnimation != PrimaryTag.WALK) {
|
||||
instance.setFrame(lastWalkFrame);
|
||||
instance.setFrame(instance.clampFrame(lastWalkFrame));
|
||||
}
|
||||
this.currentAnimation = animationName;
|
||||
this.currentAnimationSecondaryTags = secondaryAnimationTags;
|
||||
@ -130,7 +130,7 @@ public interface RenderWidget {
|
||||
allowRarityVariations);
|
||||
if (sequence != null) {
|
||||
if(lastWalkFrame != -1 && animationName == PrimaryTag.WALK && currentAnimation != PrimaryTag.WALK) {
|
||||
instance.setFrame(lastWalkFrame);
|
||||
instance.setFrame(instance.clampFrame(lastWalkFrame));
|
||||
}
|
||||
this.currentAnimation = animationName;
|
||||
this.currentAnimationSecondaryTags = secondaryAnimationTags;
|
||||
|
@ -114,30 +114,9 @@ public class CSimulation implements CPlayerAPI {
|
||||
for (int i = 0; i < WarsmashConstants.MAX_PLAYERS; i++) {
|
||||
final CBasePlayer configPlayer = config.getPlayer(i);
|
||||
final War3MapConfigStartLoc startLoc = config.getStartLoc(configPlayer.getStartLocationIndex());
|
||||
CRace defaultRace;
|
||||
switch(i) {
|
||||
case 0:
|
||||
defaultRace = CRace.NIGHTELF;
|
||||
break;
|
||||
case 1:
|
||||
defaultRace = CRace.UNDEAD;
|
||||
break;
|
||||
case 2:
|
||||
defaultRace = CRace.HUMAN;
|
||||
break;
|
||||
default:
|
||||
defaultRace = CRace.OTHER;
|
||||
break;
|
||||
}
|
||||
CRace defaultRace = CRace.ORC;
|
||||
final CPlayer newPlayer = new CPlayer(defaultRace, new float[] { startLoc.getX(), startLoc.getY() },
|
||||
configPlayer);
|
||||
if(i < 3) {
|
||||
for(int j = 0; j < 3; j++) {
|
||||
if(j != i) {
|
||||
newPlayer.setAlliance(j, CAllianceType.PASSIVE, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.players.add(newPlayer);
|
||||
}
|
||||
this.players.get(this.players.size() - 4).setName(miscData.getLocalizedString("WESTRING_PLAYER_NA"));
|
||||
@ -153,7 +132,6 @@ public class CSimulation implements CPlayerAPI {
|
||||
}
|
||||
|
||||
this.commandErrorListener = commandErrorListener;
|
||||
currentGameDayTimeElapsed = gameplayConstants.getGameDayLength()/2;
|
||||
|
||||
}
|
||||
|
||||
|
@ -1986,6 +1986,9 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
|
||||
}
|
||||
|
||||
private void reloadSelectedUnitUI(final RenderUnit unit) {
|
||||
if(unit == null) {
|
||||
return;
|
||||
}
|
||||
final CUnit simulationUnit = unit.getSimulationUnit();
|
||||
final float lifeRatioRemaining = simulationUnit.getLife() / simulationUnit.getMaxLife();
|
||||
this.rootFrame.setText(this.unitLifeText, FastNumberFormat.formatWholeNumber(simulationUnit.getLife()) + " / "
|
||||
@ -2419,6 +2422,9 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
|
||||
|
||||
@Override
|
||||
public void lifeChanged() {
|
||||
if(selectedUnit == null) {
|
||||
return;
|
||||
}
|
||||
if (this.selectedUnit.getSimulationUnit().isDead()) {
|
||||
final RenderUnit preferredSelectionReplacement = this.selectedUnit.getPreferredSelectionReplacement();
|
||||
final List<RenderWidget> newSelection;
|
||||
|
Loading…
Reference in New Issue
Block a user